Repository: SiCKRAGE/SiCKRAGE
Branch: master
Commit: 6cf2428dc146
Files: 571
Total size: 12.3 MB
Directory structure:
gitextract_ei3lbocf/
├── .changelogrc
├── .dockerignore
├── .eslintrc
├── .gitattributes
├── .gitignore
├── .gitlab-ci.yml
├── CHANGELOG.md
├── COPYING.txt
├── Dockerfile
├── MANIFEST.in
├── README.txt
├── SiCKRAGE.py
├── build_protos.bat
├── changelog-template.md
├── checksum-generator.py
├── checksum-validator.py
├── crowdin.yaml
├── docker-compose.yml
├── manifests/
│ ├── deployment.yaml
│ ├── ingress.yaml
│ └── service.yaml
├── package.json
├── protos/
│ ├── announcement_v1.proto
│ ├── network_timezone_v1.proto
│ ├── search_provider_url_v1.proto
│ ├── server_certificate_v1.proto
│ └── updates_v1.proto
├── readme.md
├── renovate.json
├── requirements-dev.txt
├── requirements.txt
├── runscripts/
│ ├── init.debian
│ ├── init.fedora
│ ├── init.freebsd
│ ├── init.gentoo
│ ├── init.solaris11
│ ├── init.systemd
│ ├── init.ubuntu
│ └── init.upstart
├── setup.cfg
├── setup.py
├── sickrage/
│ ├── __init__.py
│ ├── autoProcessTV/
│ │ ├── __init__.py
│ │ ├── autoProcessTV.cfg.sample
│ │ ├── autoProcessTV.py
│ │ ├── hellaToSiCKRAGE.py
│ │ ├── mediaToSiCKRAGE.py
│ │ └── sabToSiCKRAGE.py
│ ├── checksums.md5
│ ├── clients/
│ │ ├── __init__.py
│ │ ├── nzb/
│ │ │ ├── __init__.py
│ │ │ ├── download_station.py
│ │ │ ├── nzbget.py
│ │ │ └── sabnzbd.py
│ │ └── torrent/
│ │ ├── __init__.py
│ │ ├── deluge.py
│ │ ├── deluged.py
│ │ ├── download_station.py
│ │ ├── mlnet.py
│ │ ├── putio.py
│ │ ├── qbittorrent.py
│ │ ├── rtorrent.py
│ │ ├── transmission.py
│ │ └── utorrent.py
│ ├── core/
│ │ ├── __init__.py
│ │ ├── amqp/
│ │ │ ├── __init__.py
│ │ │ ├── consumer.py
│ │ │ └── protos/
│ │ │ ├── announcement_v1_pb2.py
│ │ │ ├── network_timezone_v1_pb2.py
│ │ │ ├── search_provider_url_v1_pb2.py
│ │ │ ├── server_certificate_v1_pb2.py
│ │ │ └── updates_v1_pb2.py
│ │ ├── announcements.py
│ │ ├── api/
│ │ │ ├── __init__.py
│ │ │ └── exceptions.py
│ │ ├── auth/
│ │ │ └── __init__.py
│ │ ├── auto_backup.py
│ │ ├── blackandwhitelist.py
│ │ ├── caches/
│ │ │ ├── __init__.py
│ │ │ ├── image_cache.py
│ │ │ ├── name_cache.py
│ │ │ └── tv_cache.py
│ │ ├── classes.py
│ │ ├── common.py
│ │ ├── config/
│ │ │ ├── __init__.py
│ │ │ └── helpers.py
│ │ ├── databases/
│ │ │ ├── __init__.py
│ │ │ ├── cache/
│ │ │ │ ├── __init__.py
│ │ │ │ └── migrations/
│ │ │ │ ├── env.py
│ │ │ │ ├── script.py.mako
│ │ │ │ └── versions/
│ │ │ │ ├── 001_Add_Initial_Tables.py
│ │ │ │ ├── 002_Remove_ID_Column_From_LastSearch_Table.py
│ │ │ │ ├── 003_Rename_IndexerID_To_SeriesID_On_Provider_Table.py
│ │ │ │ ├── 004_Add_OAuth2Token_Table.py
│ │ │ │ ├── 005_Add_Announcements_Table.py
│ │ │ │ ├── 006_Add_Session_State_Column_To_OAuth2Token_Table.py
│ │ │ │ ├── 007_Add_Token_Type_Column_To_OAuth2Token_Table.py
│ │ │ │ ├── 008_Drop_QuickSearch_Tables.py
│ │ │ │ ├── 009_Add_SeriesProviderID_Column_To_Providers_Table.py
│ │ │ │ ├── 010_Remove_OAuth2Token_Table.py
│ │ │ │ └── 011_Bump_Version.py
│ │ │ ├── config/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── migrations/
│ │ │ │ │ ├── env.py
│ │ │ │ │ ├── script.py.mako
│ │ │ │ │ └── versions/
│ │ │ │ │ ├── 001_Add_Initial_Tables.py
│ │ │ │ │ ├── 002_Remove_Web_Host_Column.py
│ │ │ │ │ ├── 003_Remove_Search_Providers_Newznab_Key_Column.py
│ │ │ │ │ ├── 004_Add_SSO_API_Key_Column_To_General_Table.py
│ │ │ │ │ ├── 005_Convert_Default_Series_Provider_Language_Code_To_ISO6393_In_General_Table.py
│ │ │ │ │ ├── 006_Bump_Version.py
│ │ │ │ │ ├── 007_Convert_NMA_Priority_Column_To_Integer.py
│ │ │ │ │ ├── 008_Add_Update_Video_Metadata_Column_To_General_Table.py
│ │ │ │ │ └── 009_Add_AutoBackup_Columns_To_General_Table.py
│ │ │ │ └── schemas.py
│ │ │ └── main/
│ │ │ ├── __init__.py
│ │ │ ├── migrations/
│ │ │ │ ├── env.py
│ │ │ │ ├── script.py.mako
│ │ │ │ └── versions/
│ │ │ │ ├── 001_Add_Initial_Tables.py
│ │ │ │ ├── 002_Add_Last_Backlog_Search_Column_To_TVShow_Table.py
│ │ │ │ ├── 003_Add_Last_Proper_Search_Column_To_TVShow_Table.py
│ │ │ │ ├── 004_Rename_Columns_On_TVShow_Table.py
│ │ │ │ ├── 005_Rename_Columns_On_IMDbInfo_Table.py
│ │ │ │ ├── 006_Rename_Columns_On_TVEpisode_Table.py
│ │ │ │ ├── 007_Convert_Airdate_Column_To_Date_Type_On_TVEpisode_Table.py
│ │ │ │ ├── 008_Convert_Date_Column_To_DateTime_Type_On_FailedSnatchHistory_Table.py
│ │ │ │ ├── 009_Convert_Date_Column_To_DateTime_Type_On_History_Table.py
│ │ │ │ ├── 010_Add_Release_Group_Column_To_History_Table.py
│ │ │ │ ├── 011_Add_Scene_Exceptions_Column_To_TVShow_Table.py
│ │ │ │ ├── 012_Add_Search_Format_Column_To_TVShow_Table.py
│ │ │ │ ├── 013_Add_Scene_Column_To_TVShow_Table.py
│ │ │ │ ├── 014_Add_Last_XEM_Refresh_Column_To_TVShows_Table.py
│ │ │ │ ├── 015_Add_XEM_Numbering_To_TVEpisodes_Table.py
│ │ │ │ ├── 016_Merge_Scene_Numbering_Table_With_TVEpisodes_Table.py
│ │ │ │ ├── 017_Convert_SearchFormat_Column_To_Enum_Type_On_TVShow_Table.py
│ │ │ │ ├── 018_Convert_Timestamp_Integer_Columns_To_DateTime_Type_On_TVEpisode_Table.py
│ │ │ │ ├── 019_Convert_Timestamp_Integer_Columns_To_DateTime_Type_On_TVShow_Table.py
│ │ │ │ ├── 020_Convert_Timestamp_Integer_Columns_To_DateTime_Type_On_ImdbInfo_Table.py
│ │ │ │ ├── 021_Upgrade_To_SiCKRAGE_v10.py
│ │ │ │ ├── 022_Convert_Language_Codes_To_ISO6393_On_TVShow_Table.py
│ │ │ │ └── 023_Bump_Version.py
│ │ │ └── schemas.py
│ │ ├── enums.py
│ │ ├── exceptions/
│ │ │ └── __init__.py
│ │ ├── google_drive.py
│ │ ├── helpers/
│ │ │ ├── __init__.py
│ │ │ ├── anidb.py
│ │ │ ├── browser.py
│ │ │ ├── encryption.py
│ │ │ ├── metadata.py
│ │ │ ├── show_names.py
│ │ │ └── srdatetime.py
│ │ ├── imdb_popular.py
│ │ ├── logger/
│ │ │ └── __init__.py
│ │ ├── media/
│ │ │ ├── __init__.py
│ │ │ ├── banner.py
│ │ │ ├── fanart.py
│ │ │ ├── network.py
│ │ │ ├── poster.py
│ │ │ └── util.py
│ │ ├── nameparser/
│ │ │ ├── __init__.py
│ │ │ ├── regexes.py
│ │ │ └── validator.py
│ │ ├── nzbSplitter.py
│ │ ├── process_tv.py
│ │ ├── processors/
│ │ │ ├── __init__.py
│ │ │ ├── auto_postprocessor.py
│ │ │ ├── failed_processor.py
│ │ │ └── post_processor.py
│ │ ├── queues/
│ │ │ ├── __init__.py
│ │ │ ├── postprocessor.py
│ │ │ ├── search.py
│ │ │ └── show.py
│ │ ├── scene_numbering.py
│ │ ├── search.py
│ │ ├── searchers/
│ │ │ ├── __init__.py
│ │ │ ├── backlog_searcher.py
│ │ │ ├── daily_searcher.py
│ │ │ ├── failed_snatch_searcher.py
│ │ │ ├── proper_searcher.py
│ │ │ ├── subtitle_searcher.py
│ │ │ └── trakt_searcher.py
│ │ ├── traktapi.py
│ │ ├── tv/
│ │ │ ├── __init__.py
│ │ │ ├── episode/
│ │ │ │ ├── __init__.py
│ │ │ │ └── helpers.py
│ │ │ └── show/
│ │ │ ├── __init__.py
│ │ │ ├── coming_episodes.py
│ │ │ ├── helpers.py
│ │ │ └── history.py
│ │ ├── ui.py
│ │ ├── updaters/
│ │ │ ├── __init__.py
│ │ │ ├── rsscache_updater.py
│ │ │ ├── show_updater.py
│ │ │ └── tz_updater.py
│ │ ├── upnp.py
│ │ ├── version_updater.py
│ │ ├── webserver/
│ │ │ ├── __init__.py
│ │ │ ├── handlers/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── account.py
│ │ │ │ ├── announcements.py
│ │ │ │ ├── api/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── schemas.py
│ │ │ │ │ ├── v1/
│ │ │ │ │ │ └── __init__.py
│ │ │ │ │ └── v2/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── config/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── schemas.py
│ │ │ │ │ ├── episode/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── schemas.py
│ │ │ │ │ ├── file_browser/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── schemas.py
│ │ │ │ │ ├── history/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── schemas.py
│ │ │ │ │ ├── postprocess/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── schemas.py
│ │ │ │ │ ├── schedule/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── schemas.py
│ │ │ │ │ ├── series/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── schemas.py
│ │ │ │ │ └── series_provider/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── schemas.py
│ │ │ │ ├── base.py
│ │ │ │ ├── calendar.py
│ │ │ │ ├── changelog.py
│ │ │ │ ├── config/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── anime.py
│ │ │ │ │ ├── backup_restore.py
│ │ │ │ │ ├── general.py
│ │ │ │ │ ├── notifications.py
│ │ │ │ │ ├── postprocessing.py
│ │ │ │ │ ├── providers.py
│ │ │ │ │ ├── quality_settings.py
│ │ │ │ │ ├── search.py
│ │ │ │ │ └── subtitles.py
│ │ │ │ ├── google_drive.py
│ │ │ │ ├── history.py
│ │ │ │ ├── home/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── add_shows.py
│ │ │ │ │ └── postprocess.py
│ │ │ │ ├── login.py
│ │ │ │ ├── logout.py
│ │ │ │ ├── logs.py
│ │ │ │ ├── manage/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── queues.py
│ │ │ │ ├── not_found.py
│ │ │ │ ├── root.py
│ │ │ │ └── web_file_browser.py
│ │ │ ├── helpers.py
│ │ │ └── views/
│ │ │ ├── announcements.mako
│ │ │ ├── api_builder.mako
│ │ │ ├── config/
│ │ │ │ ├── anime.mako
│ │ │ │ ├── backup_restore.mako
│ │ │ │ ├── general.mako
│ │ │ │ ├── index.mako
│ │ │ │ ├── notifications.mako
│ │ │ │ ├── postprocessing.mako
│ │ │ │ ├── providers.mako
│ │ │ │ ├── quality_settings.mako
│ │ │ │ ├── search.mako
│ │ │ │ └── subtitles.mako
│ │ │ ├── errors/
│ │ │ │ └── 500.mako
│ │ │ ├── generic_message.mako
│ │ │ ├── history.mako
│ │ │ ├── home/
│ │ │ │ ├── add_existing_shows.mako
│ │ │ │ ├── add_shows.mako
│ │ │ │ ├── display_show.mako
│ │ │ │ ├── edit_show.mako
│ │ │ │ ├── imdb_shows.mako
│ │ │ │ ├── index.mako
│ │ │ │ ├── mass_add_table.mako
│ │ │ │ ├── new_show.mako
│ │ │ │ ├── postprocess.mako
│ │ │ │ ├── provider_status.mako
│ │ │ │ ├── restart.mako
│ │ │ │ ├── server_status.mako
│ │ │ │ ├── test_renaming.mako
│ │ │ │ └── trakt_shows.mako
│ │ │ ├── includes/
│ │ │ │ ├── add_show_options.mako
│ │ │ │ ├── blackwhitelist.mako
│ │ │ │ ├── modals.mako
│ │ │ │ ├── quality_chooser.mako
│ │ │ │ ├── quality_defaults.mako
│ │ │ │ └── root_dirs.mako
│ │ │ ├── layouts/
│ │ │ │ ├── config.mako
│ │ │ │ └── main.mako
│ │ │ ├── login.mako
│ │ │ ├── login_failed.mako
│ │ │ ├── logs/
│ │ │ │ ├── errors.mako
│ │ │ │ └── view.mako
│ │ │ ├── manage/
│ │ │ │ ├── backlog_overview.mako
│ │ │ │ ├── episode_statuses.mako
│ │ │ │ ├── failed_downloads.mako
│ │ │ │ ├── mass_edit.mako
│ │ │ │ ├── mass_update.mako
│ │ │ │ ├── queues.mako
│ │ │ │ ├── subtitles_missed.mako
│ │ │ │ └── torrents.mako
│ │ │ └── schedule.mako
│ │ ├── websession/
│ │ │ └── __init__.py
│ │ └── websocket/
│ │ └── __init__.py
│ ├── libs/
│ │ ├── __init__.py
│ │ ├── adba/
│ │ │ ├── __init__.py
│ │ │ ├── aniDBAbstracter.py
│ │ │ ├── aniDBcommands.py
│ │ │ ├── aniDBerrors.py
│ │ │ ├── aniDBfileInfo.py
│ │ │ ├── aniDBlink.py
│ │ │ ├── aniDBmaper.py
│ │ │ ├── aniDBresponses.py
│ │ │ └── aniDBtvDBmaper.py
│ │ ├── fanart/
│ │ │ ├── __init__.py
│ │ │ ├── errors.py
│ │ │ ├── immutable.py
│ │ │ ├── items.py
│ │ │ ├── movie.py
│ │ │ ├── music.py
│ │ │ └── tv.py
│ │ ├── rtorrentlib/
│ │ │ ├── __init__.py
│ │ │ ├── common.py
│ │ │ ├── err.py
│ │ │ ├── file.py
│ │ │ ├── group.py
│ │ │ ├── lib/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── bencode.py
│ │ │ │ ├── torrentparser.py
│ │ │ │ └── xmlrpc/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── basic_auth.py
│ │ │ │ ├── http.py
│ │ │ │ ├── requests_transport.py
│ │ │ │ └── scgi.py
│ │ │ ├── peer.py
│ │ │ ├── rpc/
│ │ │ │ └── __init__.py
│ │ │ ├── torrent.py
│ │ │ └── tracker.py
│ │ ├── trakt/
│ │ │ ├── __init__.py
│ │ │ ├── client.py
│ │ │ ├── core/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── configuration.py
│ │ │ │ ├── context_collection.py
│ │ │ │ ├── context_stack.py
│ │ │ │ ├── emitter.py
│ │ │ │ ├── errors.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── helpers.py
│ │ │ │ ├── http.py
│ │ │ │ ├── keylock.py
│ │ │ │ ├── pagination.py
│ │ │ │ └── request.py
│ │ │ ├── helpers.py
│ │ │ ├── hooks.py
│ │ │ ├── interfaces/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── auth.py
│ │ │ │ ├── base/
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── calendars.py
│ │ │ │ ├── movies/
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── oauth/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── device.py
│ │ │ │ │ └── pin.py
│ │ │ │ ├── recommendations.py
│ │ │ │ ├── scrobble.py
│ │ │ │ ├── search.py
│ │ │ │ ├── shows/
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── sync/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── collection.py
│ │ │ │ │ ├── core/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── mixins.py
│ │ │ │ │ ├── history.py
│ │ │ │ │ ├── playback.py
│ │ │ │ │ ├── ratings.py
│ │ │ │ │ ├── watched.py
│ │ │ │ │ └── watchlist.py
│ │ │ │ └── users/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── lists/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── list_.py
│ │ │ │ └── settings.py
│ │ │ ├── mapper/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── comment.py
│ │ │ │ ├── core/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── base.py
│ │ │ │ ├── list.py
│ │ │ │ ├── list_item.py
│ │ │ │ ├── search.py
│ │ │ │ ├── summary.py
│ │ │ │ └── sync.py
│ │ │ ├── objects/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── comment.py
│ │ │ │ ├── core/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── helpers.py
│ │ │ │ ├── episode.py
│ │ │ │ ├── list/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── base.py
│ │ │ │ │ └── custom.py
│ │ │ │ ├── media.py
│ │ │ │ ├── movie.py
│ │ │ │ ├── person.py
│ │ │ │ ├── rating.py
│ │ │ │ ├── season.py
│ │ │ │ ├── show.py
│ │ │ │ └── video.py
│ │ │ ├── sphinxext.py
│ │ │ └── version.py
│ │ └── upnpclient/
│ │ ├── __init__.py
│ │ ├── const.py
│ │ ├── errors.py
│ │ ├── marshal.py
│ │ ├── soap.py
│ │ ├── ssdp.py
│ │ ├── upnp.py
│ │ └── util.py
│ ├── locale/
│ │ ├── af_ZA/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ar_SA/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ca_ES/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── cs_CZ/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── da_DK/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── de_DE/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── el_GR/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── en_US/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── es_ES/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── fi_FI/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── fr_FR/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── he_IL/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── hu_HU/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── it_IT/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ja_JP/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ko_KR/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── messages.pot
│ │ ├── nl_NL/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── no_NO/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── pl_PL/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── pt_BR/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── pt_PT/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ro_RO/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ru_RU/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── sr_SP/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── sv_SE/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── tr_TR/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── uk_UA/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── vi_VN/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── zh_CN/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ └── zh_TW/
│ │ └── LC_MESSAGES/
│ │ ├── messages.mo
│ │ └── messages.po
│ ├── metadata_providers/
│ │ ├── __init__.py
│ │ ├── kodi.py
│ │ ├── kodi_12plus.py
│ │ ├── mede8er.py
│ │ ├── mediabrowser.py
│ │ ├── ps3.py
│ │ ├── tivo.py
│ │ └── wdtv.py
│ ├── notification_providers/
│ │ ├── __init__.py
│ │ ├── alexa.py
│ │ ├── boxcar2.py
│ │ ├── discord.py
│ │ ├── emailnotify.py
│ │ ├── emby.py
│ │ ├── freemobile.py
│ │ ├── growl.py
│ │ ├── join.py
│ │ ├── kodi.py
│ │ ├── libnotify.py
│ │ ├── nma.py
│ │ ├── nmj.py
│ │ ├── nmjv2.py
│ │ ├── plex.py
│ │ ├── prowl.py
│ │ ├── pushalot.py
│ │ ├── pushbullet.py
│ │ ├── pushover.py
│ │ ├── pytivo.py
│ │ ├── slack.py
│ │ ├── synoindex.py
│ │ ├── synology.py
│ │ ├── telegram.py
│ │ ├── trakt.py
│ │ ├── tweet.py
│ │ └── twilio_notifer.py
│ ├── search_providers/
│ │ ├── __init__.py
│ │ ├── nzb/
│ │ │ ├── __init__.py
│ │ │ ├── anizb.py
│ │ │ └── binsearch.py
│ │ └── torrent/
│ │ ├── 1337x.py
│ │ ├── __init__.py
│ │ ├── abnormal.py
│ │ ├── alpharatio.py
│ │ ├── bitcannon.py
│ │ ├── btn.py
│ │ ├── danishbits.py
│ │ ├── filelist.py
│ │ ├── gktorrent.py
│ │ ├── hd4free.py
│ │ ├── hdbits.py
│ │ ├── hdspace.py
│ │ ├── hdtorrents.py
│ │ ├── hounddawgs.py
│ │ ├── immortalseed.py
│ │ ├── iptorrents.py
│ │ ├── kat.py
│ │ ├── limetorrents.py
│ │ ├── magnetdl.py
│ │ ├── morethantv.py
│ │ ├── ncore.py
│ │ ├── nebulance.py
│ │ ├── newpct.py
│ │ ├── norbits.py
│ │ ├── nyaatorrents.py
│ │ ├── pretome.py
│ │ ├── scenetime.py
│ │ ├── shazbat.py
│ │ ├── speedcd.py
│ │ ├── thepiratebay.py
│ │ ├── tokyotoshokan.py
│ │ ├── torrentbytes.py
│ │ ├── torrentday.py
│ │ ├── torrentleech.py
│ │ ├── torrentproject.py
│ │ ├── torrentz.py
│ │ ├── tvchaosuk.py
│ │ ├── xthor.py
│ │ └── yggtorrent.py
│ ├── series_providers/
│ │ ├── __init__.py
│ │ ├── cache.py
│ │ ├── exceptions.py
│ │ ├── helpers.py
│ │ └── thetvdb.py
│ ├── subtitles/
│ │ ├── __init__.py
│ │ ├── converters/
│ │ │ ├── __init__.py
│ │ │ └── subscene.py
│ │ ├── providers/
│ │ │ ├── __init__.py
│ │ │ ├── itasa.py
│ │ │ ├── subscene.py
│ │ │ ├── utils.py
│ │ │ └── wizdom.py
│ │ └── refiners/
│ │ ├── __init__.py
│ │ ├── release.py
│ │ └── tv_episode.py
│ └── version.txt
├── src/
│ ├── app.js
│ ├── js/
│ │ └── core.js
│ └── scss/
│ └── core.scss
├── tests/
│ ├── __init__.py
│ └── test_web.py
├── tox.ini
└── webpack.config.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .changelogrc
================================================
{
"app_name": "",
"logo": "https://sickrage.ca/img/logo-stacked.png",
"intro": "",
"branch" : "",
"repo_url": "",
"version_name" : "",
"file": "CHANGELOG.md",
"template": "changelog-template.md",
"sections": [
{
"title": "Bug Fixes",
"grep": "^Fix"
},
{
"title": "Features",
"grep": "^Feat"
},
{
"title": "Documentation",
"grep": "^Docs"
},
{
"title": "Breaking changes",
"grep": "BREAKING"
},
{
"title": "Refactor",
"grep": "^Refactor"
},
{
"title": "Style",
"grep": "^Style"
},
{
"title": "Test",
"grep": "^Test"
},
{
"title": "Chore",
"grep": "^Chore"
},
{
"title": "Branchs merged",
"grep": "^Merge branch"
},
{
"title" : "Pull requests merged",
"grep": "^Merge pull request"
}
]
}
================================================
FILE: .dockerignore
================================================
.git
.gitlab
.gitignore
.gitattributes
.eslintc
**/__pycache__
**/*.py[cod]
src
tests
runscripts
node_modules
dist
manifests
CHANGELOG.md
readme.md
README.txt
crowdin.yaml
MANIFEST.in
package.json
package-lock.json
pre-commit-hook.sh
setup.cfg
setup.py
webpack.config.js
================================================
FILE: .eslintrc
================================================
{
"env": {
"browser": true,
"es6": true,
"node": true,
"jquery": true
},
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"ecmaFeatures": {
"jsx": false
}
},
"parser": "babel-eslint",
"plugins": [],
"extends": "eslint:recommended",
"rules": {
"no-console": "off",
"no-unused-vars": "off"
}
}
================================================
FILE: .gitattributes
================================================
# Set the default behavior, in case people don't have core.autocrlf set.
# Handle line endings automatically for files detected as text
# and leave all files detected as binary untouched.
* text=auto
#
# The above will handle all files NOT found below
#
#
## These files are text and should be normalized (Convert crlf => lf)
#
# git config
.gitattributes text
.gitignore text
# Documentation
*.md text
CHANGES text
# Startup script
init.* text
# Various
*.ini text
*.txt text
*.less text
*.h text
*.in text
# Python Source files
*.pxd text
*.py text
*.py3 text
*.pyw text
*.pyx text
# Mako template
*.mako text
# Web file
*.htm text
*.html text
*.css text
*.js text
*.xml text
#
## These files are binary and should be left untouched
#
# Python Binary files
*.db binary
*.p binary
*.pkl binary
*.pyc binary
*.pyd binary
*.pyo binary
# These files are binary and should be left untouched
# (binary is a macro for -text -diff)
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.swf binary
*.gz binary
*.zip binary
*.7z binary
*.ttf binary
*.svg binary
*.woff binary
*.eot binary
*.rar binary
*.dll binary
*.lib
================================================
FILE: .gitignore
================================================
# SR AniDB Files #
######################
/Session.cfg
/sickrage/libs/adba/anime-list.xml
/sickrage/libs/adba/animetitles.xml
# SR GitLab Files #
######################
/.gitlab/
# SR Travis-CI Files #
######################
/.travis.yml
/.travis/
# SR User Related #
######################
*.db*
*.torrent
*.magnet
config.ini
swagger.json
privatekey.pem
autoProcessTV.cfg
/.imdbpie_cache/
/server.crt
/server.key
/sickrage/unrar/
# SR Test Related #
######################
/tests/data/
/.tox/
report.xml
# Compiled Source #
######################
*.py[cod]
# IDE Specific #
######################
*.bak
*.tmp
*.wpr
*.project
*.pydevproject
*.cproject
*.tmproj
*.tmproject
*.sw?
*.ipr
.pypirc
Session.vim
sickrage.egg-info
/.idea
/.ropeproject/*
/.settings/*
/build/
pre-commit-hook.sh
/venv/
/.vagrant/
Vagrantfile
# OS Generated Files #
######################
desktop.ini
ehthumbs.db
Thumbs.db
.Spotlight-V100
/.Trashes
/.directory
/.DS_Store
# Build Files #
######################
.yarn-cache
package-lock.json
/bower_components/
/node_modules/
/src/spritesmith-generated/
/dist/
/sickrage/core/webserver/static/js/core.js.map
/cargo/
================================================
FILE: .gitlab-ci.yml
================================================
stages:
# - review_webpack
# - review_docker
# - review_deploy
# - test
- build
# - sentry
- deploy
- publish
#review:webpack:
# stage: review_webpack
# image:
# name: nikolaik/python-nodejs:python3.7-nodejs10-alpine
# variables:
# NODE_ENV: "development"
# script:
# - apk add --no-cache git gcc libffi-dev python3-dev musl-dev openssl-dev
# - npm install
# - npm run build
# only:
# - merge_requests@SiCKRAGE/sickrage
# cache:
# key: ${CI_COMMIT_REF_SLUG}
# paths:
# - sickrage/core/webserver/static/
#
#review:docker:
# stage: review_docker
# dependencies:
# - review:webpack
# image:
# name: docker:latest
# entrypoint: ["/bin/sh", "-c"]
# variables:
# DOCKER_DRIVER: overlay2
# DOCKER_HOST: tcp://localhost:2375
# DOCKER_TLS_CERTDIR: ""
# services:
# - docker:dind
# script:
# - docker login -u "${CI_REGISTRY_USER}" -p "${CI_JOB_TOKEN}" "${CI_REGISTRY}"
# - docker build --network host -t "${CI_REGISTRY_IMAGE}:latest" .
# - docker tag "${CI_REGISTRY_IMAGE}:latest" "${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_NAME}"
# - test ! -z "${CI_COMMIT_TAG}" && docker push "${CI_REGISTRY_IMAGE}:latest"
# - docker push "${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_NAME}"
# only:
# - merge_requests@SiCKRAGE/sickrage
# cache:
# key: ${CI_COMMIT_REF_SLUG}
#
#review:deploy:
# stage: review_deploy
# dependencies:
# - review:docker
# image:
# name: lachlanevenson/k8s-kubectl:latest
# entrypoint: ["/bin/sh", "-c"]
# script:
# - kubectl create secret docker-registry gitlab-registry --namespace ${KUBE_NAMESPACE} --docker-server=${CI_REGISTRY} --docker-username=${CI_REGISTRY_USER} --docker-password=${CI_JOB_TOKEN} --docker-email=$GITLAB_USER_EMAIL --dry-run -o json | kubectl apply --namespace ${KUBE_NAMESPACE} -f -
# - sed -i "s~__CI_REGISTRY_IMAGE__~${CI_REGISTRY_IMAGE}~" manifests/deployment.yaml
# - sed -i "s/__VERSION__/${CI_COMMIT_REF_NAME}/" manifests/deployment.yaml manifests/ingress.yaml manifests/service.yaml
# - sed -i "s/__CI_COMMIT_REF_SLUG__/${CI_COMMIT_REF_SLUG}/" manifests/deployment.yaml manifests/ingress.yaml manifests/service.yaml
# - sed -i "s/__CI_ENVIRONMENT_SLUG__/${CI_ENVIRONMENT_SLUG}/" manifests/deployment.yaml manifests/ingress.yaml manifests/service.yaml
# - sed -i "s/__KUBE_NAMESPACE__/${KUBE_NAMESPACE}/" manifests/deployment.yaml manifests/ingress.yaml manifests/service.yaml
# - |
# if kubectl apply -f manifests/deployment.yaml | grep -q unchanged; then
# echo "=> Patching deployment to force image update."
# kubectl patch -f manifests/deployment.yaml -p "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"ci-last-updated\":\"$(date +'%s')\"}}}}}"
# else
# echo "=> Deployment apply has changed the object, no need to force image update."
# fi
# - kubectl apply -f manifests/service.yaml || true
# - kubectl apply -f manifests/ingress.yaml
# - kubectl rollout status -f manifests/deployment.yaml
# environment:
# name: review/$CI_COMMIT_REF_NAME
# url: https://review.sickrage.ca/$CI_COMMIT_REF_SLUG
# on_stop: review:stop
# only:
# - merge_requests@SiCKRAGE/sickrage
#
#review:stop:
# stage: review_deploy
# image:
# name: lachlanevenson/k8s-kubectl:latest
# entrypoint: ["/bin/sh", "-c"]
# script:
## - wget -O /usr/bin/reg https://github.com/genuinetools/reg/releases/download/v0.13.0/reg-linux-amd64
## - chmod +x /usr/bin/reg
## - reg -r ${CI_REGISTRY} -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} rm ${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_NAME}
# - kubectl delete ing -l ref=${CI_ENVIRONMENT_SLUG}
# - kubectl delete all -l ref=${CI_ENVIRONMENT_SLUG}
# variables:
# GIT_STRATEGY: none
# when: manual
# environment:
# name: review/$CI_COMMIT_REF_NAME
# action: stop
# only:
# - merge_requests@SiCKRAGE/sickrage
#.test_template: &test
# stage: test
# retry: 1
# image:
# name: python:$PYTHON_VERSION
# variables:
# ASYNC_TEST_TIMEOUT: 60
# script:
# - pip install tox
# - tox -e $TOX_ENV
# artifacts:
# when: always
# reports:
# junit: report.xml
# paths:
# - report.xml
# expire_in: 1 week
# except:
# refs:
# - tags
# - triggers
# variables:
# - $CI_COMMIT_BRANCH == "master"
# - $CI_COMMIT_BRANCH == "i10n_develop"
# - $CI_COMMIT_MESSAGE =~ /\[TASK\] Pre-Releasing/
# - $CI_COMMIT_MESSAGE =~ /\[TASK\] Bump/
#
#test_py36:
# <<: *test
# variables:
# TOX_ENV: "py36"
# PYTHON_VERSION: "3.6"
#
#test_py37:
# <<: *test
# variables:
# TOX_ENV: "py37"
# PYTHON_VERSION: "3.7"
#
#test_py38:
# <<: *test
# variables:
# TOX_ENV: "py38"
# PYTHON_VERSION: "3.8"
#
#test_py39:
# <<: *test
# variables:
# TOX_ENV: "py39"
# PYTHON_VERSION: "3.9"
#
#test_py310:
# <<: *test
# variables:
# TOX_ENV: "py310"
# PYTHON_VERSION: "3.10"
build_master:
stage: build
image:
name: nikolaik/python-nodejs:python3.10-nodejs14-alpine
variables:
NODE_ENV: "development"
CARGO_HOME: "$CI_PROJECT_DIR/cargo"
script:
- export PATH="$CARGO_HOME/bin:$PATH"
- apk add --no-cache git gcc libffi-dev python3-dev musl-dev openssl-dev curl unzip
- curl https://sh.rustup.rs -sSf | sh -s -- -y
- git config --global user.email $(git --no-pager show -s --format='%ae' HEAD)
- git config --global user.name $(git --no-pager show -s --format='%an' HEAD)
- pip install -U pip
- pip install bumpversion
- pip install -r requirements-dev.txt
- bumpversion --allow-dirty release package.json sickrage/version.txt sickrage/__init__.py
- RELEASE_VERSION=$(awk -F '"' '/^__version__/ {print $2}' sickrage/__init__.py)
- npx auto-changelog -v $RELEASE_VERSION --hide-credit --package --commit-limit false --ignore-commit-pattern \[TASK\].*
- npm install
- npm run build
- python checksum-generator.py
- git checkout -b release/$RELEASE_VERSION
- git fetch --all
- git add --all
- git commit -m "[TASK] Releasing v$RELEASE_VERSION"
- git checkout master
- git fetch --all
- git merge release/$RELEASE_VERSION
- git tag -a $RELEASE_VERSION -m "Release v$RELEASE_VERSION master"
- git push https://$GITLAB_CI_USER:$GITLAB_CI_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git HEAD:master --follow-tags
- git checkout develop
- git merge --ff-only release/$RELEASE_VERSION
- bumpversion --allow-dirty patch package.json sickrage/version.txt sickrage/__init__.py
- RELEASE_VERSION=$(awk -F '"' '/^__version__/ {print $2}' sickrage/__init__.py)
- python checksum-generator.py
- git add --all
- git commit -m "[TASK] Bump develop branch to v$RELEASE_VERSION"
- git push https://$GITLAB_CI_USER:$GITLAB_CI_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git HEAD:develop --follow-tags
when: manual
only:
- /^[0-9.]+dev[0-9]+$/@SiCKRAGE/sickrage
except:
refs:
- branches
- triggers
variables:
- $CI_COMMIT_MESSAGE =~ /\[TASK\] Releasing/
build_develop:
stage: build
retry: 2
image:
name: nikolaik/python-nodejs:python3.10-nodejs14-alpine
variables:
NODE_ENV: "development"
CARGO_HOME: "$CI_PROJECT_DIR/cargo"
script:
- export PATH="$CARGO_HOME/bin:$PATH"
- apk add --no-cache git gcc libffi-dev python3-dev musl-dev openssl-dev curl
- curl https://sh.rustup.rs -sSf | sh -s -- -y
- npm install
- pip install -U pip
- pip install bumpversion
- pip install -r requirements-dev.txt
- bumpversion --allow-dirty dev package.json sickrage/version.txt sickrage/__init__.py
- RELEASE_VERSION=$(awk -F '"' '/^__version__/ {print $2}' sickrage/__init__.py)
- npx auto-changelog -v $RELEASE_VERSION --hide-credit --unreleased --package --commit-limit false --ignore-commit-pattern \[TASK\].*
- npm run build
- python checksum-generator.py
- python setup.py extract_messages
- python setup.py init_catalog -l en_US
- python setup.py compile_catalog
- git config --global user.email $(git --no-pager show -s --format='%ae' HEAD)
- git config --global user.name $(git --no-pager show -s --format='%an' HEAD)
- git add --all
- git commit -m "[TASK] Pre-Releasing v$RELEASE_VERSION"
- git tag -a $RELEASE_VERSION -m "Pre-release v$RELEASE_VERSION"
- git push https://$GITLAB_CI_USER:$GITLAB_CI_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git HEAD:$CI_COMMIT_REF_NAME --follow-tags
only:
- develop@SiCKRAGE/sickrage
except:
refs:
- tags
- triggers
variables:
- $CI_COMMIT_MESSAGE =~ /\[TASK\] Pre-Releasing/
- $CI_COMMIT_MESSAGE =~ /\[TASK\] Bump/
#sentry:
# stage: sentry
# retry: 2
# image:
# name: getsentry/sentry-cli
# entrypoint: [ "" ]
# script:
# - apk add --no-cache git
# - export SENTRY_URL=$SENTRY_URL
# - export SENTRY_AUTH_TOKEN=$SENTRY_AUTH_TOKEN
# - export SENTRY_ORG=$SENTRY_ORG
# - export SENTRY_PROJECT=$SENTRY_PROJECT
# - RELEASE_VERSION=$(awk -F '"' '/^__version__/ {print $2}' sickrage/__init__.py)
# - RELEASE_BRANCH=$(git branch -a --contains tags/$CI_COMMIT_REF_NAME | grep origin | sed 's/.*origin\///')
# - sentry-cli releases new --project $SENTRY_PROJECT $RELEASE_VERSION
# - sentry-cli releases set-commits --auto $RELEASE_VERSION
# - sentry-cli releases finalize $RELEASE_VERSION
## - sentry-cli releases deploys $RELEASE_VERSION new -e $RELEASE_BRANCH
# only:
# - /^[0-9.]+$/@SiCKRAGE/sickrage
# - /^[0-9.]+dev[0-9]+$/@SiCKRAGE/sickrage
# except:
# - branches
# - triggers
publish:
stage: publish
image: registry.gitlab.com/gitlab-org/release-cli:latest
script:
- release-cli create --name "Release $CI_COMMIT_TAG" --tag-name $CI_COMMIT_TAG
only:
- tags
pypi:
stage: deploy
retry: 2
image: python:3.8-alpine3.12
variables:
CARGO_HOME: "$CI_PROJECT_DIR/cargo"
script:
- export PATH="$CARGO_HOME/bin:$PATH"
- apk add --no-cache py-pip gcc libffi-dev python3-dev musl-dev openssl-dev curl
- curl https://sh.rustup.rs -sSf | sh -s -- -y
- pip install -U pip
- pip install -U twine
- sed -i "s/^__install_type__ = [\"']\(.*\)[\"']/__install_type__ = \"pip\"/" sickrage/__init__.py
- python setup.py sdist bdist_wheel
- twine upload dist/*
only:
- /^[0-9.]+$/@SiCKRAGE/sickrage
- /^[0-9.]+dev[0-9]+$/@SiCKRAGE/sickrage
except:
- branches
- triggers
docker_master:
stage: deploy
trigger:
project: sickrage/sickrage-docker
branch: master
strategy: depend
only:
- /^[0-9.]+$/@SiCKRAGE/sickrage
except:
- branches
- triggers
docker_develop:
stage: deploy
trigger:
project: sickrage/sickrage-docker
branch: develop
strategy: depend
only:
- /^[0-9.]+dev[0-9]+$/@SiCKRAGE/sickrage
except:
- branches
- triggers
synology_master_dsm6:
stage: deploy
trigger:
project: sickrage/sickrage-synology
branch: master-dsm6
strategy: depend
only:
- /^[0-9.]+$/@SiCKRAGE/sickrage
except:
- branches
- triggers
synology_master_dsm7:
stage: deploy
trigger:
project: sickrage/sickrage-synology
branch: master-dsm7
strategy: depend
only:
- /^[0-9.]+$/@SiCKRAGE/sickrage
except:
- branches
- triggers
synology_develop_dsm6:
stage: deploy
trigger:
project: sickrage/sickrage-synology
branch: develop-dsm6
strategy: depend
only:
- /^[0-9.]+dev[0-9]+$/@SiCKRAGE/sickrage
except:
- branches
- triggers
readynas_master:
stage: deploy
variables:
UPSTREAM_COMMIT_TAG: $CI_COMMIT_TAG
UPSTREAM_PROJECT_NAME: $CI_PROJECT_NAME
UPSTREAM_COMMIT_TAG_MESSAGE: $CI_COMMIT_TAG_MESSAGE
UPSTREAM_PROJECT_ID: $CI_PROJECT_ID
trigger:
project: sickrage/sickrage-readynas
branch: master
strategy: depend
only:
- /^[0-9.]+$/@SiCKRAGE/sickrage
except:
- branches
- triggers
qnap_master:
stage: deploy
variables:
UPSTREAM_COMMIT_TAG: $CI_COMMIT_TAG
UPSTREAM_PROJECT_NAME: $CI_PROJECT_NAME
UPSTREAM_COMMIT_TAG_MESSAGE: $CI_COMMIT_TAG_MESSAGE
UPSTREAM_PROJECT_ID: $CI_PROJECT_ID
trigger:
project: sickrage/sickrage-qnap
branch: master
strategy: depend
only:
- /^[0-9.]+$/@SiCKRAGE/sickrage
except:
- branches
- triggers
================================================
FILE: CHANGELOG.md
================================================
### Changelog
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [10.0.71](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.70...10.0.71)
- added 1337x torrent provider [`0f9f562`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0f9f562fe5760e2a0283a2c26c887748251ca8ea)
- removed misc non-working public torrent providers [`35b38ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/35b38ca556f92e6013b868e9015efef3aa38dd34)
- disable tests till fixed [`a7dbfce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a7dbfce40ac32cedabb7ef63041836f9ff9cc71a)
- disable sentry in gitlab ci/cd script [`d7b1b2c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d7b1b2c3ad0fd4c9a73c597c52f9f9420952218c)
- set language for tox test env [`815b4d9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/815b4d9e4bdd3255ee2df0cf092fdb1df35db0cb)
- misc updates to plex notification client [`e9a18e7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e9a18e773d76d6ebd3c6ad9c1993ab84163a5cf3)
- disable tests till fixed [`fe2433b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fe2433b73834aac8c0bf4ca4e49c9065fc8a0c54)
#### [10.0.70](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.69...10.0.70)
> 26 September 2022
- added auto-backup feature for app data [`8689eda`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8689eda39d43af14194dcde37210b0d919893079)
- fixed issue with sabnzbd priority checkbox in ui [`97c25ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/97c25bac573cbce637d4144d82efb115668d9689)
- fixed gettext error "Cannot load translation" [`c668cd7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c668cd75a3a40a49a5e2af016c996d9ef293ffb0)
#### [10.0.69](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.68...10.0.69)
> 27 June 2022
- replaced bencode3 requirement with bencode.py [`7fcb140`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7fcb140b07f430744e2d0d455e468f242568062a)
- update renovate.json [`650ccb0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/650ccb0a31a29b21d8bc16b79f174f7680f62df0)
#### [10.0.68](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.67...10.0.68)
> 26 June 2022
- fix sentry stage in CI script [`86c0a9c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/86c0a9cddd729f29eab2d7d6fa5bae5192acb2ed)
- fix sentry stage in CI script [`56d8fcb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/56d8fcb5fe83952509e83fbc01be05f6555db714)
#### [10.0.67](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.66...10.0.67)
> 26 June 2022
- Added renovate.json file [`#42`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/42)
- bumped cryptography dependency [`bd7d884`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bd7d8843af773035acd069b7fc9a76c1b715539a)
- fix startup issue [`73ae82c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/73ae82c4facfa63ef17ca7ce8fa74e10287a388c)
- sync master <-> develop branches [`d463203`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d4632034cb443c5578fe0535e3dd933b15928c55)
- bumped cryptography dependency [`095ccb7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/095ccb7367deca2e0950ecb94a441467590f4848)
- bumped cryptography dependency [`7afab55`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7afab55c8372344c8ead4580565ce4521edff2a7)
- sync master <-> develop branches [`f772e7d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f772e7d24692af52ebf742cc41cf4c41ea151675)
- sync master <-> develop branches [`807f96e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/807f96e3366daa7e7c0435aa8cf36a94f910d856)
#### [10.0.66](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.65...10.0.66)
> 19 June 2022
- New Crowdin updates [`#40`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/40)
- New translations messages.pot (Portuguese, Brazilian) [`f9db8ad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f9db8ad9791b3bf63a539861dfe337c253629dab)
- New translations messages.pot (Danish) [`3db9bfb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3db9bfbc71ecb619c06df031054faeb14ab93d5e)
- New translations messages.pot (French) [`ddf3baa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ddf3baa529d038b1a475b713c9e8dcf43f43d535)
- New translations messages.pot (Dutch) [`a468f8a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a468f8a37d10c51f6f7fe9a1c245b353c5ccf952)
- New translations messages.pot (Norwegian) [`9743232`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/974323271cc753a59cea90cb0cb3c1bed217d2e4)
- New translations messages.pot (German) [`a0a36df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a0a36df2a2032e43df37d134a4adc55b618f2129)
- New translations messages.pot (Italian) [`76681eb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/76681eb4a51bc5d68bd7be8da5f5b499f4d00d33)
- New translations messages.pot (Vietnamese) [`7b1551a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b1551acdbbb2432b27d983bb27a441751cda9f8)
- New translations messages.pot (Portuguese) [`ed400bf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ed400bf0bb1851cc474cb656bbe764977eb3a804)
- New translations messages.pot (Romanian) [`f8cec42`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f8cec42303f1e5244dbaf147da1eb29eb70f0e8e)
- New translations messages.pot (Catalan) [`02410d1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/02410d1986bf8b8a5f08d336ac92e4b0d18737bc)
- New translations messages.pot (Finnish) [`d66da43`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d66da43dc60e56b358dce8ad49307a8d8593f71a)
- New translations messages.pot (Polish) [`dcac221`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dcac221a4e23871136e6f08c7a4f5e061d161278)
- New translations messages.pot (Hungarian) [`fe95752`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fe95752e4f1dd607934b1a92d01db21384060211)
- New translations messages.pot (Czech) [`ff25e51`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ff25e51981895982e7b4af6fdbb9b4dc3d15dbd7)
- New translations messages.pot (Greek) [`f664d91`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f664d912335bf4e930ca598f5cc1ded4255915e9)
- New translations messages.pot (Hebrew) [`ba03c87`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ba03c87fd5188b80e25dc530b239667e44448ed1)
- New translations messages.pot (Russian) [`1c4c0ed`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c4c0ed4902f0e7c272067a5221afdd401694ee8)
- New translations messages.pot (Ukrainian) [`aaa9093`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aaa9093e8ebfd67be8699c27df346edb0fc9332b)
- New translations messages.pot (Japanese) [`0401d35`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0401d355eeb8ec7304ba8fd535043847ec1231d7)
- Update source file messages.pot [`c882d05`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c882d053aaaae824db073890c4b754f9405267d2)
- Update source file messages.pot [`80de3aa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/80de3aabf8c56cf54c097ad9f0936cf35bae5cf4)
#### [10.0.65](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.64...10.0.65)
> 18 June 2022
- Fixed UnboundLocalError: local variable 'e' referenced before assignment [`15e551e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15e551ec1d177b666d4cd4c10b0eecd0181b29d5)
- Fixed UnboundLocalError: local variable 'e' referenced before assignment [`6cb1fed`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6cb1fed3efed5dcf3cbbc2c5938ae2ca300ddc00)
#### [10.0.64](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.63...10.0.64)
> 17 June 2022
- moved loading of core module to outside try/except block for init app settings [`82955e5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/82955e589d8ba99cf419ff498e4f893fa556e2ec)
- moved loading of core module to outside try/except block for init app settings [`b9e97aa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9e97aa1afa3bcd3146eabf6e4a1657dd3ba7c87)
- added missing dev depend mako to requirements-dev.txt [`1bff2fb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1bff2fbe57edd679cec068caca5066662556108d)
#### [10.0.63](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.62...10.0.63)
> 2 June 2022
- refactored log level of rarbg provider to debug for rarbg api returned errors [`619e864`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/619e8648e4329e3eacad102bcc9e9801e3ebde40)
#### [10.0.62](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.61...10.0.62)
> 9 May 2022
#### [10.0.61](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.60...10.0.61)
> 8 May 2022
- fixed issues with blank URLs being sent to get_image function when populating show/season/episode images [`bda6105`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bda61054c9b8ac46cf036413d83fd4769dfa6ae3)
#### [10.0.60](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.59...10.0.60)
> 8 May 2022
- added in missing mimetype mkv [`956a357`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/956a357160f4377e8ea2b0f86331394c322b71e4)
#### [10.0.59](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.58...10.0.59)
> 6 May 2022
- resolved gettext and fstring issues [`182a6c0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/182a6c0ae9b368a57c566965e6d65d1339786378)
- updated english translations [`2f4b447`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f4b447824dfcb2dfa0e8edd429f1cba9cf6e184)
- added retries for rarbg search provider [`dc46165`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dc4616541ba350e8f3848cc3cbc9250eb8be2d22)
#### [10.0.58](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.57...10.0.58)
> 26 March 2022
- added python version constraints for importlib-metadata in requirements.txt [`df671c9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/df671c986d78ff7555acf5836736c754df971c10)
#### [10.0.57](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.56...10.0.57)
> 22 March 2022
#### [10.0.56](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.55...10.0.56)
> 20 March 2022
#### [10.0.55](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.54...10.0.55)
> 20 March 2022
- Bumped babelfish requirement [`2dfe7dd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2dfe7dd41721812859e68b36a9c17c745b517655)
- Bumped lxml [`a750b74`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a750b748c96df323c23d4d04b6741c68ca2bfbfa)
#### [10.0.54](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.53...10.0.54)
> 17 March 2022
- Bumped PyYaml [`81c2da3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/81c2da37b21bd2c4775171394009440a0235f83c)
#### [10.0.53](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.52...10.0.53)
> 16 March 2022
- Bumped beautifulsoup4 [`6de06e8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6de06e82382da5d455fa30e1e61033229ffca631)
#### [10.0.52](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.51...10.0.52)
> 6 March 2022
- bumped protobufs to 3.19.4 [`539c633`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/539c633fb04997507130867f79b0d4048cf7561d)
#### [10.0.51](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.50...10.0.51)
> 5 March 2022
#### [10.0.50](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.49...10.0.50)
> 23 January 2022
#### [10.0.49](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.48...10.0.49)
> 22 January 2022
#### [10.0.48](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.47...10.0.48)
> 22 January 2022
#### [10.0.47](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.46...10.0.47)
> 1 January 2022
- Refactored video files to be mime typed by built-in module mimetypes, no longer requires end-user to specify allowed video file extensions [`9f0903d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9f0903deafba49880b6003bacf8fc3f579070ea0)
#### [10.0.46](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.45...10.0.46)
> 2 November 2021
#### [10.0.45](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.44...10.0.45)
> 4 October 2021
- fixed issue with show language now displaying correcting in edit show view [`8a33201`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a3320101005be49a83e9203a306180e91a128af)
#### [10.0.44](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.43...10.0.44)
> 4 October 2021
#### [10.0.43](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.42...10.0.43)
> 3 October 2021
#### [10.0.42](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.41...10.0.42)
> 3 October 2021
- fixed "Invalid image type series for series provider" [`2825d75`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2825d75d88b44a5afada143d7c18821c386f710d)
#### [10.0.41](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.40...10.0.41)
> 3 October 2021
- cleaned up oauth2 offline token migration code [`f0db748`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f0db74855dc5c3f6e466aee2dc0aa4b5fb4f4a91)
- cleaned up oauth2 offline token migration code [`2f2a708`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f2a7080e171b0852124a96758968de2b05dd812)
- skip search cache results if series provider id is none [`45ef300`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/45ef300f168a1942b2efb61941d13482956e1f53)
- updated package.json [`d42b20d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d42b20d0d49422ac82d70df1d3f4f6d70ecf83b7)
#### [10.0.40](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.39...10.0.40)
> 2 October 2021
- removed import of pycountry, not needed [`9fac4ea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9fac4ea0e6e2680a9519cf48231f75aeb5c71951)
#### [10.0.39](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.38...10.0.39)
> 2 October 2021
#### [10.0.38](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.37...10.0.38)
> 6 September 2021
#### [10.0.37](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.36...10.0.37)
> 3 September 2021
- Fixed cache database migration issues related to oauth2 and announcements tables [`d239c77`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d239c773feb2eb41459451f1aaba95caf66816eb)
#### [10.0.36](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.35...10.0.36)
> 28 August 2021
#### [10.0.35](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.34...10.0.35)
> 27 August 2021
#### [10.0.34](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.33...10.0.34)
> 27 August 2021
#### [10.0.33](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.32...10.0.33)
> 24 August 2021
#### [10.0.32](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.31...10.0.32)
> 10 August 2021
- fixed issue with network timezones and search provider urls not being updated on first use of app [`ca8aaef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ca8aaefdd124fd4dc76e596c89ef8c8325ae3504)
- fixed issue with network timezones and search provider urls not being updated on first use of app [`c1ec8ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c1ec8ce1757759c8622548a3f2c0970d81ee4053)
#### [10.0.31](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.30...10.0.31)
> 9 August 2021
- renamed newznab `key` param to `api_key` [`a5a271b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a5a271b8e523fef61e5d07d9840b5921910e28d1)
#### [10.0.30](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.29...10.0.30)
> 7 August 2021
- fixed amqp bug that caused a restart loop when updating ssl server cert/key [`827fac1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/827fac18e2d7b71334207c4c3387fa8fcfdc9b44)
#### [10.0.29](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.28...10.0.29)
> 6 August 2021
#### [10.0.28](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.27...10.0.28)
> 5 August 2021
- web ssl certificate/key locations and filenames are now hard-coded [`60d6bc3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/60d6bc367c9f94e75ad9bb3ec5ccec3ddaa8da85)
#### [10.0.27](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.26...10.0.27)
> 5 August 2021
- Fixed issues with checksum checks [`0bc9b08`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0bc9b0819fb72b8b0701107f3f36ec10746c1490)
- Fixed issues with checksum checks [`8d8d12e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8d8d12e37c5dff3f0d5d5fc7bb5fb4c05b18e881)
#### [10.0.26](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.25...10.0.26)
> 3 August 2021
- Refactored a core log entry from info to debug [`f7feab5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f7feab5c1ddd23d11ec411f75c90a307262db544)
#### [10.0.25](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.24...10.0.25)
> 3 August 2021
- Fixed ValueError sickrage.core.searchers.backlog_searcher in _get_wanted [`1633328`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1633328e43dede0070c144748f5b2dafa10eeffd)
#### [10.0.24](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.23...10.0.24)
> 2 August 2021
#### [10.0.23](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.22...10.0.23)
> 1 August 2021
- Refactored web handlers to return data and call tornado finish on resp from run_async method [`a7bffda`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a7bffda58098baab6b9392bef05ff92fbe43690c)
- Refactored web handlers to return data and call tornado finish on resp from run_async method [`7635d83`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7635d83894ecdaa8b72f5f3e3918e24eff8aa37e)
- Refactored web handlers to return data and call tornado finish on resp from run_async method [`98396dc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/98396dc7f97b2b355fee8e9271b418a65a74f370)
#### [10.0.22](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.21...10.0.22)
> 1 August 2021
- Moved websocket queue check function to webserver class [`18042f3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/18042f35c632962689f8854d24c09422ceaf666c)
#### [10.0.21](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.20...10.0.21)
> 1 August 2021
#### [10.0.20](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.19...10.0.20)
> 31 July 2021
#### [10.0.19](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.18...10.0.19)
> 30 July 2021
#### [10.0.18](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.17...10.0.18)
> 29 July 2021
#### [10.0.17](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.16...10.0.17)
> 29 July 2021
#### [10.0.16](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.15...10.0.16)
> 29 July 2021
#### [10.0.15](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.14...10.0.15)
> 28 July 2021
#### [10.0.14](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.13...10.0.14)
> 28 July 2021
- Refactored app updating for source [`9d7a3f8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9d7a3f8bf832152bdfed6eb10f71c7d18d5f7c10)
#### [10.0.13](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.12...10.0.13)
> 28 July 2021
#### [10.0.12](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.11...10.0.12)
> 28 July 2021
- Refactored episode slug to sXXeXX [`993479f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/993479fd84e3c97cc172efaf5dd5cfa395dbce3a)
- Misc fixes for series api v2 [`a86cc48`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a86cc485efd6072954a658f9741bdbfff90414c8)
- Refactored multi-project pipeline strategy to depend for CI script [`776e1f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/776e1f6e7c5dec268956e8da162982185c60e807)
- Fixed `bad substitution` error in gitlab CI script [`bd8c393`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bd8c3932237246fef5007687fc4158ded90b840e)
- Refactored gitlab CI script [`6df07cc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6df07ccfd97c99da3746509c705a67471a327d13)
- Fixed git origin URL [`5d50c4f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5d50c4fa53a2e639190e8df358c8a5780b237c56)
#### [10.0.11](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.10...10.0.11)
> 11 March 2021
- Fixed issue with show refresh tasks getting stuck due to missing dependant task being cleared prematurely [`4ddbd58`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4ddbd581468c98eed8157c4fdd23fe33a9f50b4b)
- Refactred "Malformed air date" warnings to debug messages during loading data from series providers for episodes [`cb5551d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cb5551dc037d330b3dd796babb025dcc9691bc3d)
#### [10.0.10](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.9...10.0.10)
> 21 February 2021
- Fixed issues with mass episode status editing [`3e21025`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3e21025960645f480f6b366f9fd6d6603c874e44)
- Fixed issues with mass editing show search format and default episode status [`34e22ae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/34e22ae4b3738a45eec384df72936e740bd55fcf)
#### [10.0.9](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.8...10.0.9)
> 8 February 2021
- Performed webpack [`03897ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/03897baf59f8bbf2f73449905b5c1de93be821d7)
- Fixed "Multiple rows were found for one_or_none()" exception when getting json object of episode object [`5761806`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5761806f6896148c6250c236faa489ba847258fc)
- Fixed issue with deploy of PyPi image [`18c3cbf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/18c3cbf43db10e234c3d544c0854abf614dd3ef2)
- Updated CI to use python 3.9 [`58ab668`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/58ab668fb584cc95a7534c83f3faa33be1e2308a)
#### [10.0.8](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.7...10.0.8)
> 26 January 2021
- Removed ability to set web host from settings in UI, constrained to only setting from cli. [`c17dc55`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c17dc551de4d6df4f4b20b96fb3d94bba086966e)
- Removed IRC from main layout [`87a989d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/87a989dc9f05308ea9fd6c23aad53d0249219624)
- Fixed issue with provider options not appearing in settings [`256e1df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/256e1df2636a8810cfa85120ce323f5967a7e4da)
- Replaced get_lan_ip with get_internal_ip [`fa55c2c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fa55c2c97f156755ece800e46632bb7feb36977b)
- Fixed `invalid literal for int() with base 10` when attempting to mass edit default episode statuses [`a7dd0d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a7dd0d7d8999ca6554a33dc5d4b3a3b0c4ca2033)
#### [10.0.7](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.6...10.0.7)
> 15 January 2021
#### [10.0.6](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.5...10.0.6)
> 14 January 2021
- Fixed issue with launching browser after app starts up via scheduler [`f554180`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f5541800645d5b78fb4723a9a194269fde283378)
#### [10.0.5](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.4...10.0.5)
> 14 January 2021
- Minor changes to CI script [`b9dd99c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9dd99c21200368d4a1a11eb663cd1de5beeb044)
#### [10.0.4](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.3...10.0.4)
> 14 January 2021
- Fixed issue with searching for new shows [`4d571f8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d571f8636feb1269705fc829721ac1fc7ef5860)
- Implemented abstract class in web base handler [`e9812be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e9812be71593a35b0987e30ec7135f51b98afcae)
- Fixed issues with cascade database deletions [`4e8421c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4e8421c376baedd4c2e751b435916e1e71fa85de)
- Decreased noise of saving config during auth methods [`5322d50`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5322d507dd26c57d7ccb701241ec7380d56adcc0)
- Refactored CI script to update changelog in separate stage [`18f98b0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/18f98b04ac7ca43867752c5c6b1a2ccce72c783d)
- Fixed CI script and merge issues between develop and master branches [`149d52e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/149d52ee513080b794396b5e065db71ad17dff90)
- Moved changelog creation to happen in release branch [`506bac0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/506bac022497ac9c0d1c28f24dea5df2796931b4)
- Fixed unterminated string in CI script [`4ab3dbd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4ab3dbd401afe04015c95eb27eae503b892dd9b1)
#### [10.0.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.2...10.0.3)
> 12 January 2021
- Database code for migrating py2 codernitydb files is now depreciated and removed [`88b4cdf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/88b4cdff8eb95937bcbd013bc182245e9b3445ad)
- Further work done to subtitle refiners [`a25c7df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a25c7df114ba831972aae9d5d9d58aa91dd3d258)
- When updating sub_id, mark config database dirty before saving [`db592df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/db592df88a08ec26eeb1242190928ae5647d729d)
- Misc cleanup [`b162bac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b162bac49b5a12a99fbdfd4ae28d280dfadf81d1)
- Removed left over code from testing [`619a0b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/619a0b2e60101c818e7e69a2debcdc9ed229a94f)
- During config file migration to config database, initial user is granted superuser permissions now [`c484e5e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c484e5e387cf77c288c56525084c2aa564f1ed5e)
#### [10.0.2](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.1...10.0.2)
> 11 January 2021
- Fixed issue with multi-episode naming [`dad674a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dad674ace8c9b04bffa042ea2ef289c37c10f1b3)
- Fixed issue with failed snatched episodes [`f5f44bc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f5f44bc47fd6105ed28f07a99322b3da1d00a207)
- Fixed issue with sorting poster view by name [`6c5adf0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6c5adf0d402ce514df99c012536241730806f5c1)
#### [10.0.1](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/10.0.0...10.0.1)
> 11 January 2021
- Fixed issue with database upgrades, refactored database initialization to happen after migrations and upgrades are performed [`bcd24c3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bcd24c38683de82c3fbf733c3a99ce3761a28cff)
### [10.0.0](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.223...10.0.0)
> 11 January 2021
- Config settings are now stored and encrypted into a sqlite database [`acd1757`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/acd175780cb5d948eb3fba7ceb6092e9c8c8b33a)
- Refactored config and how it handles database sessions [`574f983`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/574f983270aae904224d550e22145c3bd4f26c8e)
- Fixed issue with migration of config.ini to config.db [`3b56918`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3b56918a61555212757a10b91573e3934f4e7b38)
- Refactored to re-initialize database after alembic upgrades [`a314767`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a31476725d342adb03c1a0d9e469a8c6ec5a7b80)
- Fixed issue with setting default quality options for new/existing shows [`439c6f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/439c6f94c4d1f2eed57f1bcdd55faa65374b4a6f)
- Fixed issue with migration of config.ini to config.db [`f05bd79`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f05bd79b921e1fcbde971822cadb81c400d2e8fd)
- Fixed issue with default auth method being chosen during config migration [`fedbe48`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fedbe48c2880aedd89d6c9d91c94e29ca1864061)
- Fixed issue with configuration migration [`5780cfa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5780cfa0b59bfd7269e6b01b55817ec709818a24)
- Refactored task action_id property to action [`c51340c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c51340c69b6b3c878b729f02bcb22c86fbb2c314)
- Refactored web server write_error function to log issues using error handler [`4edc0d8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4edc0d8364e6c2218a3045029387f0426796b815)
- Refactored web handler for getting manual search statuses [`4f211c0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4f211c0875a3cba76ec7bba9cf996916cc34ae5a)
- Reverted previous changes [`f423954`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f423954f9e008864ef234b21ecffccc6c2e08df2)
- Refactored requirements to be installed one-by-one during version updates [`4c33752`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4c3375252f088c40e7053434b006c4fe7918f5a7)
- Fixed issue with quicksearch and episodes [`770cddb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/770cddb5d03d7cfc2100166f431cf3bfe05514ec)
- Fixed issue with testing torrent and nzb search clients [`ae57c6d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ae57c6d9e8f92d8ef355ba7c6866f4d51cd4cfe2)
- Fixed issue with episode status manage view [`9922419`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/992241900c499c5c30a20623399f6a225e3a90c2)
- Fixed stage names for CI script [`b416eaa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b416eaa15d7914c5c05cfba8b86e4f90f0d1fc9c)
- Fixed issue with provider cache and series provider id enum's [`063405b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/063405bde90ba81435a29da297b9fac1bc932d44)
- Fixed issue with CI script [`7822c90`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7822c90d6ad6d89d07c05a0de707c205a8dcf657)
- Fixed issues with mapped series provider id's to series id's [`1c3481f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c3481ff31dede64a8b1d542bc245d368d0eb7ac)
- Fixed issue with adding new show using custom quality settings [`d206d05`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d206d05746c2a60de77c3d3f9df6cc5650fc684a)
- Fixed issue with switching home page layout [`0303d22`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0303d22c3c47949765d6f550c4d3b19fbd0654e6)
- Fixed issue with schedule view and sorting [`81493a9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/81493a9f21d296f0e92f8071dc134c5b4e174d8e)
- Fixed issue with manage backlog overview page and overview classes [`73f1042`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/73f1042db9e5d083e61945625c245241973d161e)
- Fixed issues with adding shows from IMDb [`b3215de`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b3215debb23a1789f340a2613e7c6c486b91e2ac)
- Fixed issues with switch-over from sqlalchemy-migrate to alembic migration engine [`f7ad701`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f7ad70160e47e0a9e2a70a50920533066828d44f)
- Fixed issues with incorrect separator being used for subtitle services enabled and subtitle extra scripts [`a5350d0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a5350d0fee90c58ef4c7b594c27f9f86e2b4dc5d)
- Fixed issue with specials not being retrieved from series providers [`7b3ae92`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b3ae9233630ab11d5d12d99bc8c2528d8b2b113)
- Fixed issue with main home view and not selecting a layout choice after looking at layout choices causing a redirect to undefined [`b656661`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b65666128645106afc41e122ef5e273f42c3c093)
- Fixed incorrect passed startup command for web host setting [`2922632`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/292263287e5024faed12a1dd9957e3a67213081b)
- Fixed issue with migration of config.ini to config.db [`471da17`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/471da170f18995c7fb3d0affc98cf91cafd28c5a)
- Commented out the removal of sub_id for this present moment till further code corrections are made [`4d14a72`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d14a72e392e0989194e2858f39cdaf1103be24a)
- Performed webpack [`ac6cce3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ac6cce38cd0d6cb40b8e228b1d4899d4555021f5)
- Fixed issue with indexer caching [`992f519`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/992f51990a88f6c1764ca1b959da815e68999fc6)
- Fixed issue with searching series providers for series id by term during name parsing [`b84a57f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b84a57f1b58031503216c3bf631b6d28bd2d82b4)
- Fixed issue with being able to view debug logs [`474763e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/474763eb624ca164c94cdfb3478c2c4173d2bf3a)
- Prevent null value when adding last_xem_refresh via alembic [`e738401`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e73840191a6ac0b770284da204371817eeb047ad)
- Fixed issue with updating commit tag [`835d447`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/835d4473f62dbd95ab2670e34cbe159c87b8e72d)
- Fixed issue with forcing backlog for specific shows and passing of the series provider ID [`5f4ad57`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5f4ad5752d4192d2ddc6bcca70e179fd6c21ebfb)
- Bumped version in setup.cfg to 10.0.0.dev1 [`f4dc007`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f4dc0078adddbff6d97e5e54cd32a27b894c0a83)
- Bumped version is package.json to 10.0.0.dev1 [`606c40b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/606c40b3a5fb0dcf0388ac900ab60fc80232d393)
- Major version bump to v10.0.0 [`3131c33`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3131c33aa2067f4af610b796ff33ef5db17a7ba6)
- Fixed "has no property 'showi'" [`d0c9652`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d0c9652a6e2ca40a4661801c9b7e8a5ea348dda8)
- Fixed issue #525 - removal of shows not taking due to database commit not being executed [`d615ca6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d615ca6cfa27353c8d0c99037cfcc452a85b4fa1)
- Updated requirements.txt [`143d3b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/143d3b27e86c0a4ca981a221084f4b285e8a0b3e)
- Fixed issues with installation of requirements.txt during version updates [`cb0e3ee`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cb0e3ee825ddaea5fa3f230899d2363d1d5e2d04)
#### [9.4.223](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.222...9.4.223)
> 7 September 2020
#### [9.4.222](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.221...9.4.222)
> 31 August 2020
- Fixed issue with scene_season being non-integer [`eb54e81`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eb54e81cd1b2c3c3a715ec9d20ee4d07e50892c7)
- Updated requirements.txt [`735f900`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/735f9005bcf3fe90c342e53f7ac55cd124aa4b8f)
#### [9.4.221](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.220...9.4.221)
> 19 August 2020
- Fixed issue shutting down scheduler causing an exception which broke restart sequence [`afc00d1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/afc00d10f9641ecd158b9be1ae8b05a6e26628ea)
#### [9.4.220](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.219...9.4.220)
> 19 August 2020
- Fixed issue with duplicate scene absolute numbering, old code removed. [`0c0c07d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0c0c07d3b1bad4977201aa6fe07adb008c19e479)
- Fixed issue with provider cookie verifications [`78f9f15`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/78f9f158f01345a189962e496c8a76aa67a3ea4b)
- Fixed issues with provider results containing both an airdate and season/episode in them being matched as standard to be matched as scene_date_format instead [`2d2906e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2d2906efb5be13b8c3f1cdfaa794262c28807142)
#### [9.4.219](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.218...9.4.219)
> 12 August 2020
- Commented out automatic requirements installation at app startup, needs more work. [`fa085ad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fa085ad180c6aa5486389fa89b42bb947e1e61bd)
- Refactored requirements.txt to be conditional on python version [`4658183`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/46581833a7611e398c8fae326b0bf18ebdd471c4)
- Downgraded feedparser to v5.2.1 in requirements.txt [`35029d3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/35029d32c2c7965157ad6caaf84aa5ea08219abd)
- Refactored requirements install to use --no-deps, all depends are located in requirements.txt [`69276c9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/69276c9c13aaacef3aa6dbf1078dffda5fa0302c)
- Refactored database restores to use bulk inserts for data, performance fix. [`46496c6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/46496c6e35b617bd91eede4de163e82ee110d0d4)
- Misc cleanup of gitlab ci/cd script [`90b3a67`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90b3a6721ba7147075b93ea576ca3f2197310e60)
#### [9.4.218](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.217...9.4.218)
> 9 August 2020
- Fixed issue with v16 database migration using multiple where clauses [`135dea3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/135dea3c4cb176fefb891a8d5023731753c6810a)
#### [9.4.217](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.216...9.4.217)
> 9 August 2020
- Fixed typo in database migration script [`b821ed0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b821ed0df6f59c1cf978a0a7fdd5e829620d3c5d)
#### [9.4.216](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.215...9.4.216)
> 9 August 2020
- Refactored database backup/restore code [`96cdca4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/96cdca42ae73a78ad4274918cd935b93e1995e36)
- Misc code improvements for Plex notifier [`6c346a8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6c346a8cbedbe44e0985e3b83b7f25d30d570661)
- Misc code improvements for Plex notifier [`09466b1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/09466b1abe83cae8e45d0652194808684cff3845)
- Misc corrections [`28e7ba8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/28e7ba8264e898c59ae5e4ec6ece17c5608231ea)
#### [9.4.215](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.214...9.4.215)
> 2 August 2020
#### [9.4.214](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.213...9.4.214)
> 1 August 2020
- Fixed issues with md5 checksum hasher to be compatible with python 3.5+ [`dca0752`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dca075283e27b836146de68a5da5f91d0664a421)
- Fixed issue with episodes being prematurely saved to database [`230e4a1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/230e4a11b46145fc881186a3ed574b2437d67350)
- Fixed path issue with cleanup function for startup [`64456b5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/64456b54aaa6ab4afca20a9448586545e1f0af7d)
- Refactored Dockerfile [`d546ce0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d546ce01a9b7509bfe381f5a3adc29f3d9008fe8)
- Fixed issue when episode location is null and attempting to load from .nfo file [`a37348c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a37348c6abe356742f1e50a647ed90ae1fcdca93)
- Fixed issue with removal of unwanted files and pathlib [`ce4fe00`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ce4fe0087ee88d752b3362950fc5b62f2630fe0c)
- Disabled cleanup *temp* [`083c97d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/083c97d2b7ff22344f62ea9136191b2e86195f2e)
#### [9.4.213](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.212...9.4.213)
> 29 July 2020
- Refactored server status to show task status value string [`3d28569`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3d2856923182324aee438ddeb164f56e40976dd6)
#### [9.4.212](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.211...9.4.212)
> 28 July 2020
- Fixed #484 - Mass Update Error caused by incorrectly handling show search formats as a checkbox value when it should be a integer [`#484`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/484)
- Refreshed package.json [`933467a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/933467a2eeb1a2dab6979884e2a83faedf7fb16d)
- Refactored exception handling for search providers [`0ab3a37`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0ab3a3777c4210ebba5c2e10baabcbc4caf89015)
- Refactored web handlers to run in executor in the background, this will improve performance of UI tasks that may be blocking [`6e639c3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6e639c3b07bc3a50703364a87d4aab5434f1e7ce)
- Refactored mako templates to be looked up and stored into template dict attached to tornado app settings [`60ac65d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/60ac65d283639628a9a2ebb45f246ee4b78e3f97)
- Refactored queue system and how it handles tasks [`4c39a2d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4c39a2d4baa6cf2577e9c1387f87ee182d9661b0)
- Refactored add_episodes_to_trakt_watch_list method [`1b9ce09`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1b9ce09f3aead661c1503712836518d21f0e0f45)
- Wrapped all apscheduler tasks in try/finally clause to control running state correctly [`fccfa0e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fccfa0ef96269fab2c94a586018b5dee53854b17)
- Refactored web server to run on a separate thread instead of the main thread [`502207a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/502207ad80a332f7a98aef894c91c40b924239d6)
- Refactored fifo list to collections deque in search queue class [`c237843`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c2378437376729f0d96accc9ee80d4ec0e659827)
- Refactored scheduled jobs to be async and execute on ioloop in their own thread [`64ecdbe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/64ecdbeb0e988d7a6aae6a17ad539d0a8181cae8)
- Refactored usage of IOLoop by removing const io_loop from core and using IOLoop.current() calls instead [`6046334`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6046334370568652a611ef7b62cbfb8820b632b3)
- Delete item after queue worker function finishes [`5174141`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/51741412824d200b0a40944eaeefcdc565a87743)
- Fixed multi-thread issue with quicksearch [`a34c39d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a34c39d3eff469e3b29ed0a868c368f305ca523d)
- Misc exception handling fixes for indexers [`971e8e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/971e8e28a6ce41bc12622af0be05dd17bcce8aa4)
- Feature added to view logs in realtime from log view [`0865b23`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0865b2326717524730f3c9ebec145684c019f7b0)
- Chore - Upgraded javascript modules for building core web functions [`9869925`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9869925269cf8f09830f89dd4b99e21e02dc40e5)
- Refactored queue system to process one queue item at a time [`2a47a79`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2a47a795a371afb3b120b20fcfa74645086b1cc3)
- Refactored `settings->general->advanced->git settings` buttons [`af28199`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/af28199b61d4e59f4ec216386f13242d0f633061)
- Pinned rarfile lib to v3.1 and refactored code for testing unrar compatibility [`1809d6b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1809d6b8872fa4002c8905e0730fd4b1ea8c4508)
- Refactored deluge and transmission web session handling [`71cc101`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/71cc1012434f475c89bf021341c24f09607d5093)
- Refactored how requirements.txt is installed/upgraded, added code to upgrade PIP [`3d65769`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3d657699824b79c86d303951b4f76b38c9cf8d4c)
- Refactored app_id to server_id [`a928edb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a928edb06b436ca9495f75ae65a467aeb10f3624)
- Optimized config.py imports [`6b08659`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6b08659cae1a43f2e1c85b7e0364be4df36d9308)
- Refactored web server to start right after config is loaded [`dff5d2f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dff5d2ff8a302a6f20d13afe699ac787c9289759)
- Refactored queue system to use while loop instead of apscheduler [`3173352`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/31733525322481ef3dd04adae0566e1e0cb6511b)
- Reverted changes to gitlab ci/cd script [`abfc264`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/abfc264e75bd010231604d7d07fc802ad161b82c)
- Refactored gitlab ci/cd script [`438808f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/438808f40c0ca3f7f8bc080ff47602ffa73fc248)
- Refactored qbittorrent client web session handling [`db74410`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/db7441024f16979bd5f04efc6a53c38479c49715)
- Fixed issue with linking/unlinking sickrage account to sickrage api [`f62ed72`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f62ed7227db3bf5673e4856e0280a8b93154aaf1)
- Refactored link/unlink sickrage account to sickrage api button to hide/show based on sickrage api enable/disable toggle [`5cc3a68`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5cc3a68987096468deadfeb9912171812b963c40)
- Fixed issue with post-processing [`8758c4a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8758c4a4cb150c2b53255f4956bfd8e52caef3fb)
- Refactored putio client web session handling [`2f5c9d5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f5c9d560fd7953ca16a8344328ecaec67e83195)
- Refactored rss cache updater to fire task in ioloop executor [`5c616de`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5c616de51cf41f10667f5b7ee8e32c6068a4ac73)
- Refactored how testing auth for clients is handled [`1fc9071`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1fc907129e282b50ef9db5514708b17c27ad88e4)
- Fixed issues with app shutdown and restarts [`1325174`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1325174caa77fcc0443b24cec7223301029dd128)
- Fixed issue with task priorities and enum [`e49df65`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e49df65d510814533b83e886f2365beaf35dd1f3)
- Refactored check to see if sickrage account is linked to sickrage api [`458b9f8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/458b9f8019829aa4d7fad9b8d3d05891a27b126f)
- Fixed issue `Cannot read property 'addEventListener' of null` [`1463221`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1463221f811de8e991f27865be96bf7e7b652e8a)
- Refactored how recent shows are stored [`1dd1b7f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1dd1b7f6edf7f46395fcdf79b922140e2fee9cd2)
- Updated requirements.txt [`2e62168`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2e6216825cc0e9e3b332ba02a5bd8f8ebf64ea96)
- Refactored mvgroup regex to enforce `series` needing to proceed after show name and before season number [`0a7e81a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a7e81ad6ed66bef0c3a964357b5e8b758602b37)
- Refactored download station client web session handling [`1c5c3aa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c5c3aa2ba9f0c4cc3c0dc1af3964645ce7e6df6)
- Fixed issue with search clients and urls [`d31d933`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d31d933766868119a6dfca5000b1ff81dc72fe2b)
- Refactored web username and password to be required to save settings when enabling local auth [`2275ec6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2275ec6e49af3442952eaab08725ded67e446f76)
- Refactored how scheduled jobs are forced to run [`fbcb4b0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fbcb4b0a8ad145d4b409a964dc240154f93fdd69)
- Fixed issue with retrieving scene exception names [`dd24e5a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dd24e5a126ccaed30a5d96b6acf728f3e539e9f0)
- Misc fixes [`ab3323b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ab3323b4e1b7c2b12a6e28b99e5bcbffefac2b22)
- Refactored error logging of failed queue tasks to include task name instead of just queue name [`509aeae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/509aeaee86ad8fd59022f6801e8319dfa6f3405c)
- Fixed multi-thread issue with quicksearch [`148e067`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/148e0671a11a7b422155bbfa924d939eb25779ca)
- Refactored popup window only for when enabling sickrage api and not when disabling it [`90ea945`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90ea9457e7444706d5958a52f8fdcb0afd1cccfc)
- Refactored mlnet client web session handling [`afd84ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/afd84cea45231e53f43414897a91b7afe5828ca3)
- Refactored sickrage account <> sickrage api handler to logout existing auth tokens before creating new ones [`939eeb1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/939eeb16f620bf11e7eaa879ee17112300459afc)
- Refactored gitlab ci/cd to push only annotated tags with commits [`c5737a5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c5737a557dab2aadc6843194fefef4d28a397008)
- Refactored how web session class performs retries on connection errors [`c1352ac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c1352ac639de15067e482e141ea07fef367c398f)
- Refactored show season poster and banner image download functions to be more descriptive when failing to find a download [`2f47c45`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f47c458e4cfd0986f9a246cdf70a9e882b4d81d)
- Misc formatting fix for backlog searches [`210e722`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/210e7227ee61b5198c9d20218fac3788aa7c0e52)
- Fixed comparisons in scan_subtitle_languages [`32723c5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/32723c58c843b91c0acd99a636e31ac8307bca60)
- Fixed error message from hachoir package on import [`b8c55a6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8c55a645136b2cd295d770364ccb637a313598c)
- Refactored queue system shutdown method [`fe042f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fe042f9b11272ddfb39879b0a59de59503bed3d8)
- Refactored display show view, merged right and left legend columns into one column [`18b7d47`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/18b7d471d3c05961f0df9a8a5e3a83949dc78677)
- Fixed shutdown sequence [`016f7e8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/016f7e883558f3e259aa3f0e8ba45f9e932e03a0)
- Fixed a few typos in template_name's [`7fd4431`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7fd4431e80e657be897252449b2da2cd6636d149)
- Replaced variable in gitlab-cicd script [`8f31e82`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8f31e82ac3f0b1f320ee5764c2523717aca04fe0)
- Refactored ip whitelist helper [`1a87117`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1a8711755744893e4b7c61afe8c2c53f7a2c19ae)
- Fixed `Unsupported header value None` when attempting to link sickrage account to sickrage api [`4e9d343`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4e9d3435d14257151bce3287b4f25641a0d6a848)
- Fixed reference to scheduler from core [`f9e6b25`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f9e6b255eae95d5be54b110c3a6512305ec06dc4)
- Refactored `settings->general->interface->api` generate button [`d473f39`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d473f39a1d86efc645dcf660dad66184ee3acf7e)
- Misc import cleanup [`a6eb943`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a6eb94382e641ed34b1e7aba750a92a6ff96ce3b)
- Fixed issue with shutting down post-processor queue during updates. [`13ddc68`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/13ddc68cf9ff14583c5769108064720444c3c981)
- Fixed error handling for when a queued task fails [`9a9019c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9a9019cd50e8a76a5553e76b5b9a867dcceb3141)
- Fixed typo that was preventing scene exception lookups [`5104e13`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5104e1382c4e6bf59c9786786ba4b7345ff8fd5b)
- Placed a 30s timeout on sickrage api and sickrage auth health checks [`f3e6f42`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f3e6f42c08108f4d4c644c1b1c95db1a9985e735)
- Fixed issue with adding shows off IMDb [`617e12d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/617e12d17c17ab0287043277d808185fab3dcb91)
- Removed debug logging from current_user web base method [`9e2f78c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e2f78cfc41155d140d1cd4719f555b40a4fe341)
- Refactored search formats collection string [`aa0e659`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aa0e65962a4537009fa9753239b4b0d950537d68)
- Refactored base render function to use write instead of finish, resolves a performance issue [`fafc42a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fafc42aa13ea71e31831e68a71391e66eed1995d)
- Refactored name of function in auto_postprocessor.py from run to task [`6ef74b1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6ef74b10569dd25046d57f18827e4a33671b5a80)
- Refactored mvgroup regex to be stricter [`3db8944`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3db8944c4de3c48a64532b1e52ff7d7209464f9d)
- Fixed issue with displaying a show when no imdb info is available [`c8a763b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c8a763bfa2b6f0e2431ccdec488d95a2709ee52d)
- Fixed passing of args to thread when creating thread for queue class task [`5ff5b1e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ff5b1e91686fac3c3b5402ad2b1bd4af62710af)
- Removed async from queue run function [`34e95c9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/34e95c93435cc466dfbcc8b493e9323ceebcf92d)
- Fixed missing start of thread for queue class [`4350619`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4350619c6e64a56a8a6596cf910791b8215b6af5)
- Fixed typo [`907f445`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/907f44547e6619f9a61541c96648d9c7187d2f1d)
- Renabled mako template caching [`8430679`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/843067923593bc326328cda325c3060b198e7ed5)
- Refactored ip whitelist helper and subnet checking [`741587f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/741587fb1c4bd7087afdf9c5ad76486e738e6aac)
- Refactored ip whitelist helper [`b29f00b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b29f00bcff0c3323f83af3affc9d492a02da16bf)
- Fixed issue with repeating debug message for whitelisted helper function [`484919d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/484919d7efe8288fa7f7f891761a93f05d19dca6)
- Fixed issue with unregistering app_id when app_id is not set [`7a4d36b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7a4d36b0f29850711b88ff72befa5d36cb720294)
- Fixed issue with enabling sickrage api when auth token exists [`5a82893`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5a828937d7bcbeb98ef42fabd4926bcce008e78a)
- Fixed issue #486 - scene_default reference removed from add existing shows code, added search_format_default to be passed when adding existing shows [`9b9e717`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9b9e717ec4d45a62bfdb9a16cf781ac204a10b71)
- Fixed issue with passing web root to Docker [`57444d9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/57444d96d9ae32b58fad872f2cb7dc6e0e72ad1c)
- Fixed missing column headers for display show view [`21dd1f0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/21dd1f0e17bd28110cb2f7cd22c0755cd242d35b)
- Updated gktorrent provider URL [`d20520b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d20520bc71979f3e5b82aa6483ea66cbd3465ad1)
- Refactored auto-postprocessing task to be async [`f495891`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f49589158c79cb2ddbc30d7927e07d64dcb21dc4)
#### [9.4.211](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.210...9.4.211)
> 20 April 2020
- Refactored timezone updater to perform better when updating using bulk database transactions [`a8e4896`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a8e48962dec71914c03ea663de5b799ed58da7dd)
- Reverted small change [`e8f116e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e8f116ee99d2f67ddbe82f0ac96f9e370849c043)
#### [9.4.210](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.209...9.4.210)
> 20 April 2020
#### [9.4.209](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.208...9.4.209)
> 20 April 2020
- Fixed typo in nyaatorrents provider code [`2f710ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f710baf844b9fa856e7db33afba620a16c0f28b)
- Fixed name 'ModuleNotFoundError' is not defined error for older Python 3 versions [`53746c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/53746c73a1078e2b26760ef50c05d34858d5fd1a)
- Refactored gitlab-ci script to remove changelog create when building and deploying master branch [`5bd3790`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5bd3790e5c1130c88004ba73119c7df00a918352)
#### [9.4.208](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.207...9.4.208)
> 20 April 2020
- Removed old changelog.md [`71816be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/71816be1cd6b7c7bead63eb3565e8b91b968cb09)
- Refactored changelog creation [`022e36d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/022e36d344ef0f0706acd7b363db1c634107a583)
- Replaced cfscrape with cloudcraper in requirements [`e4695af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e4695affcedc66aabeeb0aabee2e53654db823e6)
- Fixed `Unknown format code 'd' for object of type 'str'` [`2eac392`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2eac39209671a37e47f83957184719cfa9ff8974)
- Refactored git-changelog to use a template [`2d6ce4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2d6ce4b2679730aed40b8585d232296966529d8c)
- Refactored ErrorViewer and WarningViewer classes to use collections deque with a max size of 100 to prevent memory errors. [`ec25dfe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ec25dfed73b8115375529793bd590f181d7c6b05)
- Refactored application startup to install requirements via pip if ModuleNotFound exception is thrown. [`3bddcc2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3bddcc22384ec23e3b22e4711af73a85c2adf440)
- Refactored code for adding new/existing shows, removed auto-detection of XEM scene numbering as it was falsely setting scene numbering to ON. [`caa7ddf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/caa7ddf76787f32e6f86b957636f120241397519)
- Refactored npx command for generating changelog [`877f7f5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/877f7f57bbc3169f2217431487a67beb911a460b)
- Refactored git-changelog template, removed version info. [`eeffca0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eeffca07583e562dcc0729c0f25eb14e6b35cde0)
- Refactored requirements install cmd to include `--no-cache-dir` flag when ModuleNotFound exception is thrown [`96e2baa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/96e2baa026f1db19d761e2b1de8bdd1e7c7cfb04)
- Fixed path to requirements for startup install of missing modules [`0955612`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/09556122f82ebce44adcfbd4b2e6b1e83ed40b67)
- Updated donation link URL [`31143a1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/31143a1557a4e06c6c605f68a9e65f80474e8537)
#### [9.4.207](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.206...9.4.207)
> 5 April 2020
- Removed bitsoup torrent provider [`7b2618d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b2618d182cd9f41886656c81365b0b3c8402cb5)
- Refactored some startup events to fire via io_loop callbacks instead of scheduler, resolves timezone issues related to apscheduler. [`8abfa44`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8abfa4487353e1c988aa0ec77d4b8769d6ba7091)
- Fixed issue with daily searcher setting unaired episodes to wanted that do not have an airdate. [`ff440e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ff440e4ab2145a4c0ebd3c10707f7e9c900a6098)
- Fixed missing namecache error for server status page [`b9e224f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9e224ffa4ffce65ae15c593e751d5b2c264d951)
#### [9.4.206](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.205...9.4.206)
> 1 April 2020
#### [9.4.205](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.204...9.4.205)
> 30 March 2020
- Fixed issue with adding search result episodes to search snatch history for season search results. [`cfb0ceb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cfb0ceb41c9aa4c95d40ec4c7b228484d1f329ac)
- Fixed authentication issues with QBittorrent [`72ffe67`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/72ffe67ec9dd54c11d033a976a9e3902515bfbf5)
- Fixed issue with detailed/simple view and previous episode air dates. [`c3fc910`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c3fc91048121b747fb1692dd39d50379c60c7bb4)
- Removed encryption of versioned backup files, caused issues with backing up database files. [`6fe0adf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6fe0adf9a1bf84e6e0b1560a3b0ab5b9c338be85)
- Fixed regex pattern for search client URLs to allow for extra paths [`5ed88e9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ed88e9df566bb48e83a9610d6947ca7b9f2329d)
#### [9.4.204](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.203...9.4.204)
> 13 March 2020
- Updated requirement dependencies [`c888386`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c888386521cafa46bba9c8b99cc87da878ec05e9)
- Resolved incorrect handling of indexer error for `_show_data` metadata class method. [`9004608`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9004608b8c17c9a12795bba8add3238413fb0698)
- Refactored core loading shows function to use query object from database to fill show details. [`0714833`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0714833119807efc275808ec04e458a9ee00dd34)
#### [9.4.203](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.202...9.4.203)
> 9 March 2020
- Fixed IndexError when deleting episode from show episode cache. [`69fda28`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/69fda28adf1088c8e7cd5e3bb944814bebbe5bfd)
#### [9.4.202](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.201...9.4.202)
> 8 March 2020
- Refactored nzb and torrent clients into separate folders. [`09d5fcc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/09d5fcc459b564c0508e4cc2bf507acf72f655de)
- Refactored home view to not display shows till fully loaded from initial show load, allows all other aspects of web-ui to work. [`b49e766`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b49e766ec09264b39cac3e1b14952636e4292716)
- Refactored more web handlers to be async [`bc7393a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bc7393aa3d6a66a7c2ac51a8125b313e66fcc125)
- Mako templates are now rendered on executor, resolves lockups for large renders. [`dc8df9f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dc8df9f7a4d04a5d1bbd6b9f36d2a7b0e8a67466)
- Refactored with statement for database session call to variable. [`da03a7b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/da03a7b0aa463a6ddb9ced2b6b1c8ce195d33efb)
- Fixed issue with getting result using search clients. [`d2145a1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d2145a164b680e2c55d614500486bfe5573c1213)
- Refactored shows cache to populate after database init. [`77cbb46`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/77cbb4678093e141d0e85f7962938fc37ceb710a)
- Created a scheduler just for queues. [`bbaf09a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bbaf09a5033ffc165367e940b30bad14f6a0e861)
- Bumped PNotify to v4.0.0 [`f3a0f0c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f3a0f0c6754af5e7f9766b75d9bb225becf4f55d)
- Fixed issue with home view simple taking forever to render. [`1fab208`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1fab20827a441fedf6b8a1e7172019e4feacb9dd)
- Fixed up more database session passing throughout application to help with 'database locked' exceptions [`e9cf48b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e9cf48b513cb762186f78d6338bb8b87d4558f66)
- Refactored queues to be watched via apscheduler 1s interval job. [`6c2ada5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6c2ada5a92f3e0635fa1609cc022813f81bb6947)
- Refactored RLock to be acquired/released using `with` statement inside safe_commit session method. [`80ea445`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/80ea4454a8d0e715f54d07353171ec6a0765750b)
- Misc refactor [`b102856`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b102856863fc60ef702296e11deb1bb857e054e8)
- Refactored clients get module function. [`c64e4f7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c64e4f793aecfd6c97e7bacac29e96c92dca8f0f)
- Increased max database commit attempts for "database is locked" exceptions to 50 with random sleep timer ranged 10 to 30 seconds each attempt. [`4a64aa4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4a64aa4a65839e168877fa4d4e3f75470031b11b)
- Removed left over session declares on cache and main table parent classes. [`b05bbee`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b05bbee5ff39f73c9c9312d78cf4a90aea71b741)
- Fixed issue where rollback on database transaction was not being called correctly on OperationalError exceptions. [`a7076e8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a7076e84cd6cfe947047cfe0172a947f2833892b)
- Refactored RLock to be acquired/released using `with` statement inside safe_commit session method. [`180bd6b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/180bd6b21e692f921b1608b6a3376652f27e4a10)
- Refactored `delete_episode` method to remove episode object from related show episode cache. [`97c5569`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/97c5569653dada1fec55ac173611eb643f598800)
- Fixed issue with progress bar not working. [`9b55c91`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9b55c9177c190386d6f0f4f7188036b9f781f8cd)
- Refactored lazy loading for relationships on database models to joined. [`f62514e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f62514eb8b30b9be5c096b648a6a4f0085796696)
- Populating data from indexers no longer returns false if show directory does not exist so to not raise a EpisodeNotFound exception. [`50f4c87`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/50f4c876ae54f9b2acbbffac2d51a0880f409216)
- Refactored backup to not restore privatekey.pem file when choosing not to restore config. [`32e77cd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/32e77cdbb424b5b763da837f92b9c3718e5d3384)
- Fixed issue with saving shows during shutdown/restart of app. [`6917479`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/69174798e9be7a79f884c78022fb0a085c738eeb)
- Fixed type error in determine_release_name for post-processing. [`dafcedf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dafcedfce3677278d0d6d506f171e7771342fefd)
- Converted f-string literal to formatted string. [`4814986`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/481498627ba20417750ba545028fac2c76738d05)
#### [9.4.201](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.200...9.4.201)
> 31 January 2020
- Fixed issue with retrieving images for cache [`7310f88`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7310f886a6e90eb3e124c1fb6747f372a19ae9b4)
- Fixed issue with image_type string being stripped improperly [`9763fa5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9763fa5b00588221f510ca729c372f445cf8a2ca)
- Fixed mislabeled banner image type for image cache [`d56b80e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d56b80ebf125ae65d011c4f262f0d00f6bd5d4bc)
#### [9.4.200](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.199...9.4.200)
> 31 January 2020
- Refactored `_retrieve_show_image` method to download images from fanart.tv if downloading images from indexer fails in anyway. [`92e1b2b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/92e1b2bd5695e4ed652b97f47ec3fe1efcbce9af)
- Refactored getting current user info from decoded token instead of userinfo endpoint [`a41b58f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a41b58f1358cd3945c609f12bc89ec28fe5f2881)
- Fixed issue with indexer error handling [`efb8215`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/efb8215fe556e00edf623b83fbd2f40bb6dd083f)
- Bumped guessit to v3.1.0 [`57dec5d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/57dec5d0a69d22ed344b336a6dca58c7254d632d)
- Bumped CacheControl to v0.12.6 [`ad5bf69`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ad5bf6961034ebdfcc553dff271957479cce3ebe)
- Increased default backlog search frequency to 1440 minutes (1 day) [`a6cbc19`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a6cbc1981ed2105da5d6304f68b7f4de139a7856)
- Reverted health check for providers, needs further work before considered beta. [`8a08741`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a08741865edd668b1ad2228bebdb6b37a4e69e7)
#### [9.4.199](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.198...9.4.199)
> 17 January 2020
- Fixed issues with login cookies not storing in chrome or safari browsers causing failed login attempts. [`355e96e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/355e96e688491839394d90bd48534572ce809c5a)
#### [9.4.198](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.197...9.4.198)
> 12 January 2020
#### [9.4.197](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.196...9.4.197)
> 12 January 2020
- added .yarn-cache to .gitignore [`c5992b5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c5992b5e309c446f75ca2508e07f39a84ab9d6d6)
- Replaced npm with yarn in gitlab ci/cd script [`928a029`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/928a0292858ef5faba19c7c8e0d611d2eb52f88b)
- Refactored gitlab ci/cd script to clone to a depth of 10 [`aeff0eb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aeff0eba3dcf5a6399530bce88540c9d241d5d7b)
- Removed all grunt related packages from package.json [`141db85`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/141db8547d4b55689e5cdfa2eb0a30f39b11d5d5)
- Push tags only after pushing commits was successful for gitlab ci/cd script [`5fe6a98`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5fe6a989a876566c2a0720d36a84dd75aa6600a3)
- Fixed scss import paths for fontawesome [`4ed31f0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4ed31f055a96347a932f82ea36ba6f6e94cd65d4)
- Updated nodejs to v12 for gitlab ci/cd script [`177d165`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/177d165df6c14981e26f493f3e6eca6f8d08dd9a)
- Refactored npm install command for gitlab ci/cd script [`38ac023`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/38ac02315ac6c1dd0b5886f8b3832e48797d8f95)
- Reverted git depth variable in gitlab ci/cd script [`5faa625`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5faa625df40abb661ecd8b702212c7d1bb53672b)
#### [9.4.196](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.195...9.4.196)
> 10 January 2020
- Refactored offline tokens to be revoked before being replaced, resolves issues with tokens piling up. [`92d0c0f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/92d0c0ffd8ef6c8e082d91e5dc6cd37ba7ed586b)
#### [9.4.195](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.194...9.4.195)
> 9 January 2020
- Reload database files after a restore, resolves issues with database scheme migrations. [`017b1a4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/017b1a4c94cfc5ff72857040012ce06d7fc6820e)
#### [9.4.194](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.193...9.4.194)
> 8 January 2020
- Removed footer from show cards in home view. [`5de63b9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5de63b9e276b4fa498f4745196436e4ee2c1d061)
- Refactored database `with_session` staticmethod to classmethod. [`61bd3e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/61bd3e18f67161fb85b8823b2552744eebc83920)
- Refactored OperationalError to import from sqlalchemy.exc [`803b397`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/803b39775f077017474c473c96c87645d0e97938)
- Fixed issue with replacing oauth2 token on login if token already exists. [`2849e5c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2849e5c279eb6987c4ef08c9f03c4fc6c0e39dbd)
- Misc cleanup [`a929f0b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a929f0b2ef3eb8ade113a735622a7b4f47e776c1)
#### [9.4.193](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.192...9.4.193)
> 22 December 2019
#### [9.4.192](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.191...9.4.192)
> 20 December 2019
- Increased default quality sizes for 720p and up. [`0d2fd21`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0d2fd213afbef094f19eccfa06388736b9c0e42b)
- Re-enabled manual post-processing. [`e9c5c46`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e9c5c468001296f3b8cc5521d7d674c5bf988ad3)
#### [9.4.191](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.190...9.4.191)
> 19 December 2019
- Retired torrent9 provider in favour of gktorrent. [`daea33f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/daea33f084cde5d88c72ea03abbc443f560a8607)
- Increased sqlite timeout to 20 from 10 to help with `database is locked` errors during concurrency. [`f22c2df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f22c2df7a54d3e39064d9968c0bdb674687c0378)
- Check if base url is present in download url before attempting to replace with custom url. [`339ca83`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/339ca834736594a740adf69a9e4e5cdd534b8ec0)
#### [9.4.190](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.189...9.4.190)
> 17 December 2019
#### [9.4.189](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.188...9.4.189)
> 16 December 2019
- Converting internal web calls to routines to direct calls, resolves issues with timeouts occurring. [`d3d413d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d3d413d59bb9b0c0fd081f21e53e058f863bb36b)
- Refactored default provider urls to bypass urls property when formatting urls on app startup. [`0cb3c8d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0cb3c8de2501f1b827f7ba28d2e3d8aa502f3e4f)
- Refactored naming of internal api error and external api error exception classes [`580f19e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/580f19ecc119c51d65ee6327f9c465c2aa8a9f2d)
- Refactored exception handling for `quality_from_file_meta` function. [`00d367c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/00d367c13abe7dc4a3f530c67002fd8cc65c129a)
- Fixes issue #432, outputs episode object as a dict when running episode cmd from app api. [`9cfcfa4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9cfcfa4c87fff080170a2889ec575782407f3905)
- Updated URL for YggtorrentProvider to `www2.yggtorrent.ws` [`00f2131`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/00f2131c924d455c3af6b2202db438ad5f4ad942)
- Increased sqlite pool size from 200 to 1000 [`28975f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/28975f4931e92a7b643dace7768c69c716c2a8fa)
#### [9.4.188](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.187...9.4.188)
> 9 December 2019
- Fixed an issue with version updating related to checking for number of commits behind, manual update to this version commit may be required. [`37ea161`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/37ea161e35e38bc99b16ed95e59252dd87863654)
#### [9.4.187](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.186...9.4.187)
> 8 December 2019
- update RTorrent compatibility for 0.9.x [`#37`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/37)
- update rtorrent compatibility for 0.9.x [`568403a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/568403a2faccf353eb5194a0a975f12a565b5d93)
- Disabled review for CI script [`cdb11c1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cdb11c1a0c9abb4b4bdaa6fbca2a81cef2323662)
- Restricted CI/CD jobs to upstream. [`8e6c052`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8e6c052c1e7b19b5474d8dfe074bf5325cc4c144)
- Fixing issues with CI script and stages not being triggered on pushes. [`e30e8ea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e30e8eac9987b01f7f53c3d650524981ca6ebffd)
- Fixing issues with CI script and stages not being triggered on pushes. [`c193f2f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c193f2f1ed541b27373c5b74fbd6a53d6f79da8c)
- Fixing issues with CI script and stages not being triggered on pushes. [`f99732f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f99732fa7482bc658094d2719a32a08d21be01e1)
- Disabled webpack stage for reviewing merge requests, webpack needs to be done manually before submitting a merge request online. [`d0c058b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d0c058bdf9d0b193acd0c97223f594905ffbedf8)
- Fixing issues with CI script and stages not being triggered on pushes. [`c10d945`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c10d94508971b4e354f6378a1b3dafb335a237f1)
- Disabled webpack stage for reviewing merge requests, webpack needs to be done manually before submitting a merge request online. [`c40e707`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c40e707797a2dc45fc26ddb68064632ae71be957)
- Re-enabled automatic build/release/deploy for develop branch [`ffe965b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ffe965b1a6c8425f4ecab0580d5331ef68507cc7)
- fix urllib import and usage [`6a7c4a5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6a7c4a5edf16c1b70bfc1988bfa23afe5a8e8301)
- Fixing issues with CI script and stages not being triggered on pushes. [`03c886f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/03c886f7d55caeb2508984f542a5dd46eaacb9ed)
- Moved tagging of pre-release to happen after committing changes for CI script [`e4f45b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e4f45b2de5c9932c3b6bbb9a563f38facbc8ec44)
- permit scgi URIs for rtorrent [`38489fa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/38489faf77124bd50e9ea810f4be2679af3dc0c1)
- Update sickrage/clients/rtorrent.py [`1332df2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1332df2c59375e2e3c923208e0fb0182d654b527)
- add exception logging to rtorrent client auth test [`053ade3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/053ade3e148055d85024fbeecee95da7607d2f5c)
#### [9.4.186](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.185...9.4.186)
> 28 November 2019
- Refactor CI review stage [`#28`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/28)
- Delete namespace when CI environment is stopped. [`#26`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/26)
- Fixes issue #425 - converting air-by-date to episode ID when multiple episodes... [`#25`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/25)
- Added CI/CD release stage to build app [`#24`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/24)
- Added regex for semantic versioning along with matching of each section of the... [`#20`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/20)
- Refactor gitlab cicd [`#19`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/19)
- Added ability to set webroot at startup from CLI. [`#17`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/17)
- Added ability to set webroot at startup from CLI. [`#17`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/17)
- Updated gitlab ci/cd script allowing reviews [`f31ae93`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f31ae93d97c6d67871f567668b8cffdfc02db4e6)
- Refactored websockets handler. [`ba3961e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ba3961e7291988c48344713b33acab024ec51889)
- Refactored bumpversion config to properly handle develop and master versioning schemes. [`4125ec2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4125ec22037cdf14f5bc54b6cf987506538a67f0)
- Refactoring release cycle for develop -> master [`a50e87a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a50e87aedc650252d58cd958922555009f9774e2)
- Fixed issue with adding existing shows that have episode filenames that do not contain the show name. [`dc965ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dc965bade915fff67f494b3adef73420dba53713)
- Bumped version to 9.4.186.dev1 [`6438042`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6438042a2de979afc6a908a9c85e9ab347f82fce)
- Fixed issue with unlinking accounts and destroying token [`a73aa96`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a73aa968becb1c6eac71bd11b89d6956fdd92c21)
- Updated all CI jobs with proper requirements to build cryptography [`2ab5e3a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2ab5e3a011ce32aaf5e78895a50147c5f46d0f0c)
- Fixes issue #425 - converting air-by-date to episode ID when multiple episodes for show falls on same date. [`831fbb1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/831fbb180817e63e4a2deae3965508d008c06edc)
- Pre-Release v9.4.184.dev1 [`855fbd7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/855fbd738b66e1f5d36a61b6e49b78badd462941)
- Refactored gitlab ci/cd script [`d9c6d77`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d9c6d7732230f7f964df51124d65ac72baf30c56)
#### [9.4.185](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.183...9.4.185)
> 26 November 2019
- Merging Pre-Release v9.4.184.dev9 [`#29`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/29)
- Merge branch 'develop' into 'master' [`#425`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/425)
#### [9.4.183](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.182...9.4.183)
> 5 November 2019
- Revert "Refactored main shows page to load shows via web sockets." [`932c107`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/932c107abd9b64eacdffb6b18bd6c66564627a44)
- Revert "Refactored main shows page to load shows via web sockets." [`2afbbf6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2afbbf6fdb4d27d471b1d5ad1efb4ec6b94e06cf)
- Release v9.4.183 [`94f82ef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/94f82ef67e5de5d493975d93efbb30ef0d51cbe7)
- Pre-Release v9.4.183.dev1 [`d517820`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d517820615086ffc83d91a85a6c430de3d192640)
#### [9.4.182](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.181...9.4.182)
> 4 November 2019
- Pre-Release v9.4.182.dev2 [`69602be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/69602bec7c8ecae9269957edb7203f69e05ea2f4)
- Release v9.4.182 [`bb8c6e5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bb8c6e568d9c280eb77ba68c91cb352197c46e9c)
- Pre-Release v9.4.182.dev1 [`b7b2ac4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b7b2ac46bb3b508945e1e7baa2638d0517941a75)
#### [9.4.181](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.180...9.4.181)
> 3 November 2019
- Release v9.4.181 [`6bb50b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6bb50b258ea32c57401262152a3fe6f3d4c133af)
- Pre-Release v9.4.181.dev1 [`fdc5c9d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fdc5c9d5b9b3f68e0dcdfd54883d7e7d68cd24ff)
#### [9.4.180](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.179...9.4.180)
> 3 November 2019
- Release v9.4.180 [`b9bd1dc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9bd1dccfc9cccbe66aa1eaf4c9e06c77a501c2f)
- Pre-Release v9.4.180.dev1 [`0a7c487`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a7c487c06f0201d2c59ce977429ba09ce36bd53)
#### [9.4.179](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.178...9.4.179)
> 3 November 2019
- Release v9.4.179 [`d685071`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d685071b7cff47061bbe4b9461d05e5e16c8bd4f)
- Pre-Release v9.4.179.dev1 [`16e2094`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/16e2094574e353a518092d7bf7388daab1a0b525)
#### [9.4.178](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.177...9.4.178)
> 3 November 2019
- Refactored main shows page to load shows via web sockets. [`b9b280d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9b280d708c15a2bc455c92b29763d6a3849ed6c)
- Refactored main shows page to load shows via web sockets. [`828d5f7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/828d5f75a7922a8be43a37179968adfb233a1a8a)
- Resolved issue with daylight savings and scheduler. [`8a252b5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a252b55a10c8e2e4d3704feafbd825123d4f08a)
- Fixed indenting in template for shows list [`5450dd7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5450dd7f35db9b405e2bdca57b8e54188a3cb1c5)
- Pre-Release v9.4.178.dev2 [`33f9ddf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/33f9ddf35ef53ffc1e68cd9fe54b523408de68ef)
- Pre-Release v9.4.178.dev5 [`062ac69`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/062ac69587d035b98461292f92377186146ae46d)
- Pre-Release v9.4.178.dev15 [`84a5ed4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/84a5ed4bbf18ed6a3e3c8e0b2b27a37fd5b3ebff)
- Pre-Release v9.4.178.dev13 [`add4a56`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/add4a56cfb4c3fd254f4f103a41fd5deaa82196f)
- Pre-Release v9.4.178.dev16 [`222c3ed`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/222c3ed4ad35c02cc7cfebe873f0e279a12f1152)
- Pre-Release v9.4.178.dev17 [`82ee3f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/82ee3f41cb1d45540db729a73451b199277f2178)
- Pre-Release v9.4.178.dev8 [`749ed1b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/749ed1b54fccd252218d04c670b313d6d1a67985)
- Pre-Release v9.4.178.dev6 [`0707d80`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0707d807cd106c4737ece9a837dd9c9fb8b90380)
- Release v9.4.178 [`7616019`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7616019b7f3076c511f9baeb546a1b5d6af02cf5)
- Pre-Release v9.4.178.dev12 [`60f5423`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/60f542362afa7ed92e56549c8aa6c17885a9a3d3)
- Pre-Release v9.4.178.dev9 [`d07f9f8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d07f9f8f3ace8eb9e6a2c9d65da5d10897a77671)
- Pre-Release v9.4.178.dev7 [`da38c26`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/da38c261d7f9d1a961ee28617b442f973a1950be)
- Pre-Release v9.4.178.dev4 [`8dd6f50`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8dd6f503420043288254fb3096c757178a65304f)
- Pre-Release v9.4.178.dev3 [`4cf7fbb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4cf7fbbcf9583bf4f82ec76e0a376d767a5ba750)
- Pre-Release v9.4.178.dev14 [`2537f0b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2537f0b44c56ee64634f34febe41d88e10cf9c6f)
- Pre-Release v9.4.178.dev11 [`66f810e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/66f810e9a827669f89ac0c6ff154f7c48fd2217d)
- Pre-Release v9.4.178.dev10 [`4e0a44b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4e0a44b46d222347f6fd0dc40dbf386f9de783ec)
- Pre-Release v9.4.178.dev1 [`ed9a94d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ed9a94df5d2b30ca0e0a6a18a1d96789db23e83c)
#### [9.4.177](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.176...9.4.177)
> 29 September 2019
- Release v9.4.177 [`87a6ec6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/87a6ec61a7f56a492f04d1376c85f623dd107631)
- Development version bump. [`0f10d34`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0f10d349cc1f3792472f16d061490e0cb0c24f11)
#### [9.4.176](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.175...9.4.176)
> 29 September 2019
- Release v9.4.176 [`6be984f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6be984fe6dd6e30b6a1e1d19b207f6650471f71d)
#### [9.4.175](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.174...9.4.175)
> 29 September 2019
- Update .gitlab-ci.yml [`c3aed9a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c3aed9a0178a04e1cef53977f0848b5bf4f4a1de)
- Release v9.4.175 [`43fd875`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/43fd8756da6620832f4bcbcb0a56f7296d0a099d)
- Pre-Release v9.4.175.dev1 [`d35176f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d35176f2f4efee801c12b93ebf0a6f2d3cd0e1b4)
#### [9.4.174](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.173...9.4.174)
> 18 September 2019
- Refactored speed.cd to use cookie login due to re-captcha on login forms. [`7f6bdf7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f6bdf7ab1ce4c3d6a66b6a68e721e95e6d8f466)
- Release v9.4.174 [`4a98d7f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4a98d7fe26c36cc60d73db9250758db27c191f14)
- Pre-Release v9.4.174.dev1 [`b783172`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b783172a63347e0202b6abd8e01cf570c267803a)
#### [9.4.173](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.172...9.4.173)
> 16 September 2019
- Release v9.4.173 [`73d8223`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/73d82236beaba02590f4d4800628225187c59fd2)
- Pre-Release v9.4.173.dev1 [`f354ce8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f354ce83e759c41db0e85391c1034828a0750d25)
#### [9.4.172](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.171...9.4.172)
> 16 September 2019
- Bumped version for cfscrape to v2.0.8 [`1706331`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/17063315137431858dfeb700f758e4b571694013)
- Resolved issue with enable/disable of provider daily and backlog searches. [`ae7acbe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ae7acbe0d853407610db9d000125087233095a56)
- Release v9.4.172 [`483e4db`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/483e4db337154dafa471c898ac968873b61248b0)
- Pre-Release v9.4.172.dev1 [`fa32f37`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fa32f37af8a5969d1b53816a43391c1ed86f9500)
#### [9.4.171](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.170...9.4.171)
> 14 September 2019
- Release v9.4.171 [`288e419`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/288e41982bc1116aa79dc310d3b3cf7645577289)
- Pre-Release v9.4.171.dev1 [`5eb814d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5eb814d013940fdd0bfd5ddbed7f480f5c1900d3)
#### [9.4.170](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.169...9.4.170)
> 8 September 2019
- Refactored config view for search clients to require NZB host/url to be [`e40869f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e40869fc7a3acd6d0503b4238829f7f1b9a758d3)
- Resolves issues for PosixPath being returned instead of string when trying to get subtitles path. [`7df5d8f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7df5d8f40ebfd223c25c415dc4ce770c9bc1b8bd)
- Removed un-required application ID registration code from config [`3817370`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3817370539a923888971d9fb44ac12f67524f42b)
- Release v9.4.170 [`e5ff7bc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e5ff7bc44f0546e8b19346a952268e4e0198e7e9)
#### [9.4.169](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.168...9.4.169)
> 8 September 2019
- Refactored code for getting subtitles path, strips leading slashes from [`44977d4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/44977d45f29f2f2fdb484721d1f42a5ec11a6b0b)
- Misc changes [`6f4fdcb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6f4fdcb74845d8c13486c928c62de5b8e1297931)
- Updated docker-compose file [`db675fd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/db675fdc45f02cd8f1c7561c35291ef1c30230ea)
- Pre-Release v9.4.169.dev2 [`1b448d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1b448d72f2b18fb8a38fb9171d1b8e78bdaf22db)
- Release v9.4.169 [`003aeca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/003aecaed6ba09c45e4b97baed521fbff4392a39)
- Pre-Release v9.4.169.dev1 [`d52005c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d52005c6d0e99932f1b90fd706566c582decbbcd)
- Grammar correction. [`30462b1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/30462b1f29d1f687d8604e7e511e3d525ac07f75)
#### [9.4.168](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.167...9.4.168)
> 29 August 2019
- Refactored jQuery search client code, resolves issues with form validation. [`a4e25d1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4e25d1c6293c004a30f8b28e595ca297342c873)
- Performs a database rollback for episodes that fail to post-process. [`22648d1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22648d1ec28e3c06246d06594a65bd31e90d5d9d)
- Pre-Release v9.4.168.dev2 [`10e170e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/10e170e9d46fa78139f7270d2cbcdf85046f6a4f)
- Release v9.4.168 [`4638e26`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4638e2610a7ab63c70d44c584d3867bf1f80b0ae)
- Pre-Release v9.4.168.dev1 [`0116b2e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0116b2e29a7053c49cdcf4602e319ee0bcf7e2c6)
- Refactored URL for support forums in readme [`798def6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/798def65a083ed6194cba120d701cc336665f324)
- Raised timeout from 60 to 120 for Boxcar2 notifier. [`5fd62e0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5fd62e07606ca3614c82fd981d2d180653e75249)
#### [9.4.167](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.166...9.4.167)
> 11 August 2019
- Refactored code for searching providers, was causing issues with final results correctly, results where being removed when not matching exact quality. [`25fc34f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/25fc34f9fd621fceb9ac586091c863a4c87b744a)
- Release v9.4.167 [`efc5637`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/efc5637346707ec6a65f55d069aec9c13863ee64)
- Pre-Release v9.4.167.dev1 [`9c20647`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9c20647f7942bc6bc138d3d3774adfa946210d05)
#### [9.4.166](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.165...9.4.166)
> 10 August 2019
- Release v9.4.166 [`bb5635e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bb5635ec34e1562b226ad5b98dc26f213086cbff)
- Pre-Release v9.4.166.dev1 [`f9f51d2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f9f51d24af2e7ed792301268a2af50723ca99df5)
#### [9.4.165](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.164...9.4.165)
> 4 August 2019
- Renamed cache providers column `indexer_id` to `series_id` [`e5d59c9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e5d59c9d124492d208fb8919c2ac9670ff87ec20)
- Resolved issue with int variable being used where str variable is expected when creating metadata for mede8er provider. [`365a16d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/365a16db2baf200917f2f26ade55e674289c0042)
- Release v9.4.165 [`484236b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/484236b8d2a26716084d950ce6a38e15dd54dc08)
- Pre-Release v9.4.165.dev1 [`bfd27b1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bfd27b17ac550be2d082d95f38f6cf0ccb708154)
#### [9.4.164](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.163...9.4.164)
> 3 August 2019
- Fixed issues were skipping shows during adding of existing shows would just return to home page, now correctly skips to next show to add. [`b9e1cec`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9e1cec52f2981ffb39589c148f6b917bda39b0b)
- Refactored os.path for pathlib.Path [`dae67f8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dae67f8d090cd49b0f9a807acba9a199734b9e64)
- Release v9.4.164 [`dfd9ecf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dfd9ecf67f2181a5b87b33edac766a872a278da3)
- Pre-Release v9.4.164.dev2 [`4d7edad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d7edadd052c30b04f1f1e588716e81cdfc95723)
- Pre-Release v9.4.164.dev1 [`0b1d1c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0b1d1c70d03d98e16bb070d799ce19d7795c8529)
- Refactored python version log tagging to use platform instead of sys [`4b7cdae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4b7cdaefa0af712687cfb8050ae69ce1d1fd6fa6)
#### [9.4.163](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.162...9.4.163)
> 3 August 2019
- Release v9.4.163 [`8810a83`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8810a8320b108ceca21053042357d99bcf6e0450)
- Fixed issues with startup and shutil.rmtree [`f269aa7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f269aa7ee2439896e4df2711d20bd61a52c31831)
- Fixed startup issues with pathlib.Path, passes string representation of path to shutil.rmtree. [`66c7250`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/66c72505a6047c4dc74f519d814ee7f475fd3f0d)
#### [9.4.162](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.161...9.4.162)
> 3 August 2019
- Release v9.4.162 [`faae82e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/faae82e5445111ae5ffeab2c7710cdb035fb7932)
- Pre-Release v9.4.162.dev1 [`7220352`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/72203528b8f64c2441c0438f2d1ccd32ca4af0ed)
- Fixed startup issues with pathlib.Path, passes string representation of path to shutil.rmtree. [`405dead`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/405dead306aa83c7a8427664a320dafabb74d4f1)
#### [9.4.161](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.160...9.4.161)
> 1 August 2019
- Fixed issues with startup and shutil.rmtree [`f269aa7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f269aa7ee2439896e4df2711d20bd61a52c31831)
- Release v9.4.161 [`c696d94`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c696d9414262c9b36ae29413ac857168e03d3df0)
- Pre-Release v9.4.161.dev1 [`22b5ff3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22b5ff3c1476277c2de0d52e4aa9050c1a837022)
#### [9.4.160](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.159...9.4.160)
> 1 August 2019
- Fixed issues with cleanup of python compiled files on startup [`2be1836`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2be1836ff4272f40d7a9493e55105c4f8129f4ca)
- Release v9.4.160 [`cbdb2f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cbdb2f1a774b3aa72813d0395b3d1100996d4aca)
- Pre-Release v9.4.160.dev1 [`95e4603`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/95e46036ae2b8bb510007a9992282210ddcd6555)
#### [9.4.159](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.158...9.4.159)
> 31 July 2019
- Fixed issues with saving metadata provider settings. [`89e4931`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/89e49316f05b1fd59db1901082c1766008daf8ca)
- Refactored cleanup of pyc, pyo, and __pycache__ files and folders. [`763629b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/763629b0503e47c815b5746210f0d47b077bc119)
- Release v9.4.159 [`7b9f412`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b9f412c40ba56ecedbe8d27dab174a4b6cb1f74)
- Refactored post-processing to properly handle specials. [`e210a8f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e210a8fb3bb898cb99cc16b251437d8d88c8d3c7)
- Pre-Release v9.4.159.dev1 [`cec8a87`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cec8a876a72d6c79b54f8f8990bb2cdc11c7e78b)
- Refactored download link for source installs to accommodate develop releases. [`67acc5d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/67acc5d9fabbf8e6506e061479ab8ba89253ff6c)
- Updated gitignore file [`b4f3226`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b4f32269eb581f063b08644e412070ade5c54aa2)
#### [9.4.158](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.157...9.4.158)
> 31 July 2019
- Release v9.4.158 [`5db54c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5db54c4bd649f560cca169dbab94b3e08e3b48d8)
- Fixed attribute error `'str' object has no attribute 'decode'` in version updater. [`cfbeee1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cfbeee1abb4d2a3ff76e44bbabd26a1885f8c15c)
- Pre-Release v9.4.158.dev1 [`c7a14c8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c7a14c81a2e60998ae7ad945e02b595017bd8986)
- Refactored requirements.txt to replace package hachoir3 with hachoir, hachoir3 was removed from PyPi. [`67b328e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/67b328efe075a04e6e418965358a9567d9ff08ce)
#### [9.4.157](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.156...9.4.157)
> 28 July 2019
- Refactored dynamic loading of metadata providers. [`90fe2d3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90fe2d3d3a50a0314575b9a45c3f7e3348757139)
- Release v9.4.157 [`dad896a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dad896a559fd2342dcf11f9ea1fc3ceaa3e8dd5e)
- Pre-Release v9.4.157.dev1 [`324d44f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/324d44f3a9908620c021268e17d83b24deb59340)
#### [9.4.156](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.155...9.4.156)
> 22 July 2019
- Resolved issues with marking failed snatches and retrying snatches. [`7fce356`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7fce35662d902052360241c72b662b6e3bd16150)
- Release v9.4.156 [`7d7e6e5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7d7e6e5b7e8b24745edd78416d1c3bcce2882e78)
- Pre-Release v9.4.156.dev1 [`7cea63c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7cea63c5efec648d20a5face18b359696afb0368)
#### [9.4.155](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.154...9.4.155)
> 22 July 2019
- Updated copyright notices. [`19624f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/19624f654f1fb2fbfc8bd19eac9ce35b0286e386)
- Release v9.4.155 [`56ddaf1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/56ddaf16574654c59a25ac537e937baf2552f9f9)
- Pre-Release v9.4.155.dev1 [`a70aaea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a70aaea6b6189efc897a35053f5ef37b958f1ff5)
#### [9.4.154](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.153...9.4.154)
> 22 July 2019
- Release v9.4.154 [`397ac97`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/397ac97c0f46227a8809038c374d7c20ab84d598)
- Pre-Release v9.4.154.dev1 [`3079a6f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3079a6fca99dea79aa52a6b5e542fd40ca3535dd)
#### [9.4.153](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.152...9.4.153)
> 21 July 2019
- Modified startup scripts to use python3 instead of python2.7 [`5b99399`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5b993994a4f3a39d5a001d12efb7973a186ae074)
- Release v9.4.153 [`ae1a14e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ae1a14e49c7e8bebb34986d07b2bbb20b7427d9f)
- Pre-Release v9.4.153.dev1 [`db14540`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/db145403c908ec22850e567b3642458217ec1e4b)
- Modified readme.md to reflect minimum requirement of Python 3.5+ [`08f3d6a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08f3d6aad3a0f7f1a3b67a3ea173bd0e7d453f8f)
- Removed authentication requirement for robots.txt handler. [`eb4cf0a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eb4cf0ae6e218a937cb128c6c687995a835137b5)
#### [9.4.152](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.151...9.4.152)
> 21 July 2019
- Lowered requirement for Python to 3.5+ [`16043b6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/16043b63feb0ac9c14e204c2d5f9dc7cef3a0784)
- Release v9.4.152 [`31f9db2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/31f9db26785bbc91e540995405d61cbd6592502f)
- Pre-Release v9.4.152.dev1 [`927bc42`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/927bc42cb7f709bc0414d134a2f64ffc4c1c2adb)
#### [9.4.151](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.150...9.4.151)
> 21 July 2019
- When trying to determine season/episode numbers for air-by-date shows [`2f4076d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f4076d8f491e4e676ce4c0c7e1aac007892869a)
- Previous archived episodes will now be set to downloaded with original [`4806e15`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4806e15eb34483b4d99597a64a1eb785204f39c7)
- Release v9.4.151 [`54a1397`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/54a1397b22906ba90051e067502592ce28e04c31)
- Fixed issue for NZBGet downloads returning error `decorator() takes 1 positional argument but 2 were given` [`57ea9ff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/57ea9ffbcbdbb5cb5d4c50bfba4899ce43032a11)
- Pre-Release v9.4.151.dev1 [`81939c2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/81939c28d3dbcc8322fbbafdbd624f7662e5e627)
#### [9.4.150](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.149...9.4.150)
> 20 July 2019
- Refactored how source updates are handled. [`a805f32`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a805f3247e5a58c09c43312fb13d22f0359dd222)
- Release v9.4.150 [`6a275ed`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6a275ed12f72e5b0922b69a89c1137a5f28c35ab)
- Pre-Release v9.4.150.dev1 [`c419de0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c419de010904b45206bcb33860eb9b5fb235959a)
#### [9.4.149](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.148...9.4.149)
> 20 July 2019
- Fixed issues with unlinking account from application. [`05c4140`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/05c414015c1593c2f57d4ee7947c0826230a0052)
- Release v9.4.149 [`fbcf2b4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fbcf2b481d638af8d3c38cad46b681737a30d3e8)
- Pre-Release v9.4.149.dev1 [`1999b15`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1999b1567a0db4b1f4e0e1d740197bb44db0761a)
#### [9.4.148](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.147...9.4.148)
> 20 July 2019
- Release v9.4.148 [`ce02111`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ce0211119dcfc4c3c5cb311a94e62ea348d63eee)
- Pre-Release v9.4.148.dev1 [`ac21414`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ac214149b46ff4679ceea8fb33099b70c2d086db)
#### [9.4.147](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.146...9.4.147)
> 20 July 2019
- Release v9.4.147 [`a702972`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a702972a0b3663cb9dd75cdabc125e3ba44aac6e)
- Pre-Release v9.4.147.dev1 [`c2e5d67`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c2e5d67041523f5118a3b9f08ea500abfddc4f78)
- Decodes output when checking for installed PIP version to convert from [`ae4c4b1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ae4c4b1a047cadfd0630af575ded452740ba3dd8)
#### [9.4.146](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.145...9.4.146)
> 20 July 2019
- No longer need to use url_concat for requests. [`ca7e94e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ca7e94e3e62872a24c7ed65e31f777adb401714f)
- Release v9.4.146 [`130a23b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/130a23bd9b08211ce0b3252e4dd5ccd03a160327)
- Pre-Release v9.4.146.dev1 [`9c6fc09`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9c6fc098957f577ff79b5acaf2ff01ee89833af6)
#### [9.4.145](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.144...9.4.145)
> 20 July 2019
- Pre-Release v9.4.145.dev2 [`2b93b28`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2b93b2856440adc4d47170ba3d28f4dc0f8c667c)
- Release v9.4.145 [`971d032`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/971d03215d67dd9b317933199c495e10e3fb7f08)
- Checks for episode number in provider result episodes list before attempting to remove it. [`a339f1f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a339f1f6ba3bbf5a1bdf1af088dc130ae28b8102)
- Pre-Release v9.4.145.dev1 [`30f6bd1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/30f6bd1be4ba0a8c5c86f453b4b5bc900c0aab5b)
#### [9.4.144](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.143...9.4.144)
> 17 July 2019
- Release v9.4.144 [`88af882`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/88af882666d3092e9678163dd6297575035142aa)
- Pre-Release v9.4.144.dev1 [`c7b8a46`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c7b8a466f3336144c09a444d5cb9e00d34d53331)
#### [9.4.143](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.142...9.4.143)
> 17 July 2019
- Release v9.4.143 [`1155881`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/115588118522957b3476c7270398a81c409547c0)
- Pre-Release v9.4.143.dev1 [`bb11dd5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bb11dd5b7decaff3db72a3d3591500d561e0aa0f)
#### [9.4.142](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.141...9.4.142)
> 17 July 2019
- Release v9.4.142 [`692f9b1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/692f9b1cfcd43db4509844272259d00cfb29ee06)
#### [9.4.141](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.140...9.4.141)
> 16 July 2019
- Release v9.4.141 [`d4bb52b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d4bb52b2ab4d4a54214a56fda5494f4dfbf92005)
#### [9.4.140](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.139...9.4.140)
> 16 July 2019
- Release v9.4.140 [`bf8ba35`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bf8ba3540b083a080bc37cd50e75a1d5b02929cf)
#### [9.4.139](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.138...9.4.139)
> 16 July 2019
- Refactored using data to using json in requests. [`578ab74`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/578ab748cc26c62fcf4fa1da68c55c4fdbb2333b)
- Pre-Release v9.4.139.dev2 [`e749806`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e74980679886635b0add287480a94c8d3f77e262)
- Release v9.4.139 [`0f153a4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0f153a4336c2a948fa31679b1ca329c4b9038e2f)
- Pre-Release v9.4.139.dev1 [`7139f44`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7139f448203018f53462263ef103927347bd1f50)
#### [9.4.138](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.137...9.4.138)
> 14 July 2019
- Release v9.4.138 [`6c1a44f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6c1a44f0e3960b52e52dbe5798b6d2c60a1250b5)
- Pre-Release v9.4.138.dev1 [`5745352`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5745352886984d9ccb472e9542ccb048a4bfbc34)
#### [9.4.137](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.136...9.4.137)
> 14 July 2019
- Fixed schedule category sorting. [`5fe263f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5fe263f3fe4cebc23e778d5e563326ca6938e998)
- Release v9.4.137 [`f3e6803`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f3e68034c06e971b45ce787b52d1cc53c73e896a)
- Pre-Release v9.4.137.dev1 [`e12dfb5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e12dfb570e6ba2d37a81c0137a4533cc648217c3)
#### [9.4.136](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.135...9.4.136)
> 14 July 2019
- Fixed download issues for Deluge Web-UI Client. [`dd3a9a6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dd3a9a6084fb234db8691c51f2d1df99d019fd31)
- Release v9.4.136 [`e6daa57`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e6daa572f7c7a246c4ae2c95917377abedcdbba3)
#### [9.4.135](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.134...9.4.135)
> 14 July 2019
- Release v9.4.135 [`9a12a64`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9a12a645c4af25cb4c2d9cd871b8374f0d6e0dd0)
#### [9.4.134](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.133...9.4.134)
> 14 July 2019
- Resolved issue with renaming episodes not including metadata files. [`2e0b68b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2e0b68b3444009493802ef32a289d80a11d596fd)
- Pre-Release v9.4.134.dev2 [`985b907`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/985b907b4fd95651586f127327c6715d3105ea4d)
- Pre-Release v9.4.134.dev7 [`83aec60`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/83aec6047a0588f1ad3bf01b116624c6ceeacb56)
- Pre-Release v9.4.134.dev6 [`0583b04`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0583b040c89955f8609d07a3eaca79d61d325eb9)
- Release v9.4.134 [`de4f179`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/de4f179d9cfb0b81c4ac8b72562991c94344d253)
- Pre-Release v9.4.134.dev5 [`57198a8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/57198a80d20175090ef6bf18fcfcfefeca522661)
- Pre-Release v9.4.134.dev4 [`5d6bcf5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5d6bcf5c9c85fe31fdb140c52b73e5194560af25)
- Pre-Release v9.4.134.dev3 [`e9c169f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e9c169ffe1b65aca5d5f0e157904d577e622eeb0)
- Pre-Release v9.4.134.dev1 [`6b7e8bb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6b7e8bba72d6bf064e576f950c88cabb427f5220)
#### [9.4.133](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.132...9.4.133)
> 13 July 2019
- Refactoring database tests. [`3e7748e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3e7748e54fdddf1bfd36dc9f64e643ff638fc730)
- Release v9.4.133 [`9aa3996`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9aa3996478978a75d96c2350bebf3f72c64319f2)
- Pre-Release v9.4.133.dev1 [`63d34e6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/63d34e6d1c12b27ad0d509e31dc1ecee94340a40)
#### [9.4.132](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.131...9.4.132)
> 13 July 2019
- Fixes issues with mass editing shows and setting qualities. [`1175f63`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1175f634694268a94ab10898c79df6a7758e4ea3)
- Release v9.4.132 [`fc3b301`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fc3b301799316aac5ac23ab0e8d82fbc848794fe)
- Updated git release flow. [`999475f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/999475fc04666532c7f3fae6db29bc89a2d2e4c1)
- Resolved issue with setting proxy address when global proxy configured. [`7b0f1bf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b0f1bfbb4d128e9dcb43c23ba281784608da927)
- Pre-Release v9.4.132.dev1 [`faeabc9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/faeabc9473e7284506e562fc108f9706ed4c6c03)
#### [9.4.131](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.130...9.4.131)
> 13 July 2019
- Fixed issue with gitlab-ci and pipelines for master branch. [`4df45f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4df45f161996e3a6199be3c95699e9c4fbf62cfc)
- Release v9.4.131 [`4072c47`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4072c47a255a1c0b180bf02fbdbd04d2d071e398)
- Pre-Release v9.4.131.dev1 [`f7067e9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f7067e98798a4e46bd1f92fce4e6dc8eda297d02)
#### [9.4.130](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.129...9.4.130)
> 13 July 2019
- Release v9.4.130 [`368e70c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/368e70c185050d2a3ca41b1681e2b669b0baafe2)
#### [9.4.129](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.128...9.4.129)
> 13 July 2019
- Release v9.4.129 [`9628b36`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9628b3657b82a0f1f34bf45cb96543e7456ccc3e)
#### [9.4.128](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.127...9.4.128)
> 13 July 2019
- Release v9.4.128 [`705d0bd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/705d0bda1d9fc7435361092756fe5d193e189291)
#### [9.4.127](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.126...9.4.127)
> 13 July 2019
- Release v9.4.127 [`45aab9a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/45aab9af9858484f57cb05eff4b85e5273d1d9b9)
#### [9.4.126](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.125...9.4.126)
> 13 July 2019
- Release v9.4.126 [`32308be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/32308beb65137eb8630e6247a454e31bc4a4ec9c)
#### [9.4.125](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.124...9.4.125)
> 13 July 2019
- Refactored release flow. [`0ff1e9d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0ff1e9d821017f738102d167e5a7deb9e6dd4e53)
- Updated gruntfile. [`bc7c359`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bc7c35998ff6f4575164e3d009d44097f814b9d1)
- Release v9.4.125 [`a411278`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a411278c61e6794015ef692d0ee5c9f414bd7302)
- Changed close to remove for database sessions being access from web handlers, helps resolve QueuePool overflow issues. [`b9ea97e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9ea97eb33917cb5d59707d52d4bd471a496c80f)
- Merge tag '9.4.124' into develop [`ecc4ad7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ecc4ad7c43574581d95a376b21c5dd211a068f3d)
#### [9.4.124](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.122...9.4.124)
> 12 July 2019
- Pre-Release v9.4.124.dev1 [`1ad0be6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1ad0be62db17a5f34be52bb25339fddfd97cad31)
- Release v9.4.124 [`65f3178`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/65f31787404cf7dd90229e654b90ed169501c4ad)
- Pre-Release v9.4.124.dev2 [`c878cc0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c878cc06a2ebd0b760d4bcb2d022970f6ed444dc)
- Merge tag '9.4.122' into develop [`4bf4a79`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4bf4a79c199ad18610e8c94c3f2347a785070a43)
- Merge tag '9.4.122' into develop [`d37bdcd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d37bdcd25105f094bb0def5e0a478b03c100f22d)
#### [9.4.122](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.120...9.4.122)
> 12 July 2019
- Updated gruntfile. [`3e2a870`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3e2a87007c762b096046e9f0e48cba687ddd5121)
- Pre-Release v9.4.122 [`9e9f867`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e9f867fe05714066332d87d9ae839b6b9436852)
- Pre-Release v9.4.121 [`7d9f054`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7d9f054135beb2b324bade0bef6d39e93b1b15c9)
- Pre-Release v9.4.120 [`7e3a1e8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7e3a1e8843957996babe2a7d907ce2be4c5e7a0b)
- Release v9.4.122 [`3923c2d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3923c2d090c315492f6da052862a196e35e07574)
- Merge tag '9.4.120' into develop [`37d1c92`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/37d1c92859bb09920b8cd4bec10904dacf924851)
#### [9.4.120](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.119...9.4.120)
> 12 July 2019
- Migrated Docker builds to their own repository. [`01678da`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/01678da7bcd22092c7756e623ec87b0904f90c50)
- Pre-Release v9.4.120.dev1 [`17ee7fb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/17ee7fbb1a0f1ff04789bc22ba4814502c9baebe)
- Release v9.4.120 [`a586ca0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a586ca0433b1139605797f21e06f223c2e25e509)
- Merge tag '9.4.119' into develop [`523b457`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/523b4579b9ea752aa78bfb2935eb5c2787b87969)
#### [9.4.119](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.118...9.4.119)
> 11 July 2019
- Resolved issue for saving custom qualities, black/white lists, and scene exceptions. [`edc07c8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/edc07c8d7fb00a2a23c3c82a1a3297ad15bb7cc8)
- Release v9.4.119 [`30e8a1b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/30e8a1b7d5f073b12b0b6c986be16ec166f0f884)
- Resolves `can't concat str to bytes` in sickrage.providers in _get_season_search_strings [`3b88e82`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3b88e82e0ee0c59a66722a564b3b5b751c127625)
- Merge tag '9.4.118' into develop [`a52948d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a52948d19a5a56adeaf150093f0d0f7eb61121c9)
#### [9.4.118](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.117...9.4.118)
> 10 July 2019
- Release v9.4.118 [`63354dc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/63354dce53a4b3888c8a3d25945e4252891f183a)
- Places search result from indexer into list object if returned as dict. [`f6fce27`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f6fce27667b2859843e2bf5cfef57a9d62baa095)
- Resolves error `can't concat str to bytes` in `sickrage.providers in _get_episode_search_strings` [`7ad8c0b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7ad8c0b06299462bc1ce471680e2aa4d6dff9c45)
- Resolved unsupported operand type(s) for +=: 'dict' and 'list' [`8a423fd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a423fd15bc61b20045d380802fcbd2b7069a346)
- Merge tag '9.4.117' into develop [`1548288`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/154828840a40199c1de3cea064c6e3104455f371)
#### [9.4.117](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.116...9.4.117)
> 9 July 2019
- Release v9.4.117 [`1ee3cdb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1ee3cdb90e060881b0e9a5f4054087e5cc46bc58)
- Fixed issue with post-processing and logging downloads to history when unable to determine provider result came from. [`edd6289`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/edd62897563e4b3a9399a49b203c5cddd7de2a69)
- Fixed typo in container name [`134fcfe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/134fcfe23fccb7a4234b14b591039a7ba0dccf3e)
- Merge tag '9.4.116' into develop [`a953ad5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a953ad53a2b6804808a77dccfecd943de6373f98)
#### [9.4.116](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.115...9.4.116)
> 8 July 2019
- Release v9.4.116 [`42aec55`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/42aec5573026710a0ff8d4f26292ff28d9c25a68)
- Merge tag '9.4.115' into develop [`de17715`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/de17715c33d0070779236695e40848a819d552d6)
#### [9.4.115](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.114...9.4.115)
> 8 July 2019
- Release v9.4.115 [`8f08c10`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8f08c10c2e900f58ffb573cf02529a9b30a59ea8)
- Merge tag '9.4.114' into develop [`939b921`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/939b921eaf09e65fe5979c04cf151926a9f495be)
#### [9.4.114](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.113...9.4.114)
> 8 July 2019
- Release v9.4.114 [`b0731df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0731df1538aaf17dbff3e88e29250f7f156f318)
- Merge tag '9.4.113' into develop [`daaa163`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/daaa163d3fd177c9a840fdc2a426e4765268169d)
#### [9.4.113](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.111...9.4.113)
> 8 July 2019
- Release v9.4.112 [`2df3ed9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2df3ed96967463e9d93a6335c30099e40c3b5eef)
- Release v9.4.113 [`f369fde`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f369fde9f2c9b9468660366487667c7a68a7e4a4)
- Merge tag '9.4.111' into develop [`9f19c8e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9f19c8e9aa077ebb71caa63ece67c46b460cf332)
#### [9.4.111](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.110...9.4.111)
> 8 July 2019
- Refactored GitLab CI/CD script and Dockerfiles to cut down build times. [`6b4378a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6b4378aea31ff52575c21de60db3a6e0f3f06a74)
- Release v9.4.111 [`07d2e3c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/07d2e3c3519b7b31a8af906ae854fdd54f1a59a0)
- Update Dockerfile.arm32v7 [`b861832`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8618323f0f3c4a47733f23f9eb3c3e43efee2c9)
- Merge tag '9.4.110' into develop [`d263df4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d263df474f00cfbb164b356cb76e10e218848af7)
#### [9.4.110](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.109...9.4.110)
> 8 July 2019
- Fixed issue with manually post-processing episodes, was a typo. [`9d17dfa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9d17dfa420c1901519c26f1e4328f2451aeea284)
- Release v9.4.110 [`43d40c3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/43d40c38ad8119c8c84ae79056057b3864233c32)
- Merge tag '9.4.109' into develop [`2612012`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2612012fa3d87d9c9bd0af254a96b9aba4871026)
#### [9.4.109](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.108...9.4.109)
> 7 July 2019
- Release v9.4.109 [`9521413`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9521413b70f351077e5ca7addbd1e78ec10a4f2c)
- Merge tag '9.4.108' into develop [`b877a36`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b877a3647ec8339ba44ba2b90cc88313f1e358cd)
#### [9.4.108](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.107...9.4.108)
> 7 July 2019
- Updated Docker image tags to correctly represent multi-arch [`ea56a8b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ea56a8b17f0a28c5cb59162a0c6bef9bb04174ad)
- Release v9.4.108 [`ca70d11`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ca70d11b606672eac2feaf9cd0b7535bb6d890f5)
- Merge tag '9.4.107' into develop [`447124b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/447124bab77ac74be790aae59bab27ec44354d9f)
#### [9.4.107](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.106...9.4.107)
> 7 July 2019
- Release v9.4.107 [`5b3fb85`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5b3fb85a012fa12f6e9f86194199c3b0916b8a82)
- Merge tag '9.4.106' into develop [`57cceaf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/57cceafb2094f4b41fca6ba89bb526d7e6caeb74)
#### [9.4.106](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.105...9.4.106)
> 7 July 2019
- Release v9.4.106 [`3c710c6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c710c6eee96919a560da7103fe7f936c205b3fb)
- Pre-Release v9.4.106.dev6 [`1a2908e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1a2908e11f089935dd54ad9592c212f1b1e559c0)
- Pre-Release v9.4.106.dev2 [`ab0fcd1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ab0fcd1fa9572513c99db533f95ad89390946ea9)
- Pre-Release v9.4.106.dev3 [`86e80dd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/86e80dd0493146e9e52097f3e6d50cbc57d2abef)
- Pre-Release v9.4.106.dev5 [`bd8dc67`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bd8dc67586c4ed46804bfc17548a4b5633fe381d)
- Pre-Release v9.4.106.dev4 [`c8067c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c8067c4f946cb1e8fca92cf9b7d830a093d0ed86)
- Pre-Release v9.4.106.dev1 [`b0c73bf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0c73bfd3d2b1f265184374dcf181cb9cb8341ee)
- Merge tag '9.4.105' into develop [`9ebfde2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9ebfde2307672b58191694026450ac0a3c20e41d)
#### [9.4.105](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.104...9.4.105)
> 7 July 2019
- Updated gitlab-ci.yml file [`cb5b159`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cb5b1592d53f9b48e359dfd83129ba86e2107714)
- Release v9.4.105 [`2070a5b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2070a5bed225ddcedb724fdc3c88f9d0e726f948)
- Merge tag '9.4.104' into develop [`b0838ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0838ba031edf0f0aa5ba9eb790d7188adaa5ac8)
#### [9.4.104](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.103...9.4.104)
> 7 July 2019
- Release v9.4.104 [`0a2f554`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a2f5542d08db04a197f5140905e6873bfba463f)
- Merge tag '9.4.103' into develop [`174579e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/174579eae0d8cf2111f19f8a6882e2ae6b8fdef0)
#### [9.4.103](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.102...9.4.103)
> 7 July 2019
- Release v9.4.103 [`73ad9a4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/73ad9a49863e5e5347327e29a68ae31f67223668)
- Confirms that there is a year to be added from series pieces to show directory if requested. [`331fb7b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/331fb7b29cc114bd133694a7960d89bf5f523604)
- Merge tag '9.4.102' into develop [`74ff12d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/74ff12d83d8cfefbcd470d71a982daeb584ce89d)
#### [9.4.102](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.101...9.4.102)
> 7 July 2019
- Release v9.4.102 [`e59ea00`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e59ea00f5b2cd4c7212cfbcc037bd52461dd6d8e)
- Merge tag '9.4.101' into develop [`ae8f473`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ae8f473592fb55ea4552ae47b6f5b303b0807db5)
#### [9.4.101](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.100...9.4.101)
> 6 July 2019
- Release v9.4.101 [`c768c9a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c768c9a4871e4c407813c700c04012f4c6589a94)
- Merge tag '9.4.100' into develop [`a45e606`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a45e60631a34ab8f87dbd5aaa9300f6a91963dc6)
#### [9.4.100](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.99...9.4.100)
> 6 July 2019
- Release v9.4.100 [`2f5e07c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f5e07c8d1e8ccd14c7b2728da8fe2787d26ce68)
- Merge tag '9.4.99' into develop [`e7feb74`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e7feb74d41dc63c8f3c3b1111851f5f4295ddd73)
#### [9.4.99](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.98...9.4.99)
> 6 July 2019
- Misc typo fixes. [`c8ac2d4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c8ac2d441475e4b215145d7d453aea9833b8d89b)
- Release v9.4.99 [`2f4236c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f4236c989db5325d643296dd54f673b5e5f2664)
- Looks for provider search result by URL and if exists it does not add to cache. [`5ceded0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ceded0af18cab44540e2f21410ec576de5b813f)
- Converted misc errors to warnings [`c446e18`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c446e185b9d6250e6522bc2c162fa5b0eb7aa12b)
- Resolved issue for combining quality when qualities list is empty by providing a default. [`1de0584`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1de0584abc7a975e7c08ffa8e6fd5b338929f91c)
- Passes database session object onto add keyword function to avoid database locks. [`5dff80f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5dff80fb0b06a8626b64a40a8fdc4112d6306dfd)
- Merge tag '9.4.98' into develop [`ac97203`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ac9720385eb9b9e596e8105471ace881bd4c82e3)
#### [9.4.98](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.97...9.4.98)
> 6 July 2019
- Resolves timeout issues for internal http requests. [`d426b5d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d426b5d7309c989583321c2736bc3aac516fff5f)
- Release v9.4.98 [`6ddee98`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6ddee98ef99d0eca645229cbc4c7202535b61d35)
- Merge tag '9.4.97' into develop [`9ba8828`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9ba88283373ede6e57c198b404571c3f619a0631)
#### [9.4.97](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.96...9.4.97)
> 6 July 2019
- Resolved issues with subtitle downloading. [`466bb28`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/466bb283809b4ec780f6b19647bc21ac642380eb)
- Release v9.4.97 [`0603b4c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0603b4cc9a434b1927ec344b185ab62cbd03c896)
- Pre-Release v9.4.97.dev1 [`569cda3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/569cda3416bc8fc1f3129d69c6b9b0d140d2bbb6)
- Merge tag '9.4.96' into develop [`32beab2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/32beab224bb087476abf209df5bd6e0549613158)
#### [9.4.96](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.95...9.4.96)
> 5 July 2019
- Release v9.4.96 [`97f0ddc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/97f0ddc7de51c1e2314ed7dc2a3f118cef91c72f)
- Pre-Release v9.4.96.dev1 [`fbbeec4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fbbeec4aef4700fb429c1bfb7437ad46ebd667db)
- Pre-Release v9.4.96.dev2 [`6c06ea1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6c06ea1f7b7efaf397d23a08e4845721bbaae30c)
- Resolves unbound exception for variable `imdb_exception` [`d0aae5b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d0aae5b394f9f2eb819097c3de4ab314af99f1c1)
- Performs select count on provider cache results to determine if its ok to insert provider result. [`140e129`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/140e12938db2578f38fb2ebc7990d155753dd3a1)
- Merge tag '9.4.95' into develop [`90d1ea6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90d1ea6d7676e6f74c2d807b6d8ba5dbc391a067)
#### [9.4.95](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.94...9.4.95)
> 3 July 2019
- Release v9.4.95 [`f7eea90`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f7eea9011e07db94dd73bb264c58e7842c9e5e28)
- Merge tag '9.4.94' into develop [`4d39393`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d39393385d33612c42ea1654484808318f4572d)
#### [9.4.94](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.93...9.4.94)
> 3 July 2019
- Resolves issue with saving subtitle settings. [`8fb2de7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8fb2de789668bb7b2559707cb774bf8d8e88f9dc)
- Release v9.4.94 [`0d476b6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0d476b6caaf98e9a945a3a502973a23070be2e17)
- Merge tag '9.4.93' into develop [`4d45298`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d45298148f7b1a6cb59a029a1589d94e6b21b41)
#### [9.4.93](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.92...9.4.93)
> 3 July 2019
- Resolves `a bytes-like object is required, not 'str'` [`831787e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/831787e65b2ad05aa986574abdd97f68b141ac52)
- Release v9.4.93 [`a2bfb77`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a2bfb7721a9bdcd1002334e3aac36b37f7b3b173)
- Pre-Release v9.4.93.dev1 [`d6a1ed2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d6a1ed2ef5ea3cc3f18e5f4d8e588009119c7248)
- Fixed key not found issue with migration table column mapper. [`32ed358`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/32ed35832cf7aa0c4d47918a843819049bce2a00)
- Merge tag '9.4.92' into develop [`86ed469`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/86ed469f120d8425c3a82b6c1535d4c4759870bf)
#### [9.4.92](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.91...9.4.92)
> 2 July 2019
- Refactored Deluge Daemon client to PIP install and removed old lib requirement. [`9a08345`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9a08345479bf2cfd0b84c51a5674df02a6a9f76a)
- Release v9.4.92 [`79bd8f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/79bd8f1e9ac2c60838e8a9431d37655aeeb80f1d)
- Pre-Release v9.4.92.dev1 [`60c2498`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/60c2498fb1288ddb0a7c4ed3cd4211c9a95afa88)
- Resolves version updated issue `'str' object has no attribute 'decode'` [`22240c9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22240c96a4fae5f6eb467958b7653fda6f47417c)
- Refactored display show mako code to check if imdb_info object has attribute genre. [`526b345`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/526b345cba2bccd58f2c7cbabd4082e8fe9290ee)
- Merge tag '9.4.91' into develop [`7183e59`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7183e59fb187265d6af6bc2589ab6068d505daea)
#### [9.4.91](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.90...9.4.91)
> 1 July 2019
- Resolved issues with installing requirements.txt during updates causing updates to fail. [`df757f5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/df757f507110e376ecb7b6d2bb4755366b7ad749)
- Release v9.4.91 [`3425338`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3425338989c55bcf7d2b46da0085cc1fbd0ca0de)
- Merge tag '9.4.90' into develop [`3b118f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3b118f1ea456ce4d4c7268b15853b6d219363584)
#### [9.4.90](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.89...9.4.90)
> 1 July 2019
- Release v9.4.90 [`2f63091`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f63091d3f4d17e17c8d4491a54e92fe3eb95645)
- Merge tag '9.4.89' into develop [`c272ea3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c272ea3975c718c56cbb99d5276b94426bc16e33)
#### [9.4.89](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.88...9.4.89)
> 1 July 2019
- Resolved issues with NZB searches and not snatching found results. [`c3957e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c3957e4dc5220c471721d95ffe04e73fb5febeed)
- Release v9.4.89 [`2908018`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2908018017261d407e7f083fb130d42299158de0)
- Merge tag '9.4.88' into develop [`bfb84e8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bfb84e872ce32b0328e3443e9fc1271e83320ad7)
#### [9.4.88](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.87...9.4.88)
> 1 July 2019
- Refactored how we gather query and body arguments to use one method. [`5bffa94`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5bffa94a2ec9bf3bd468924c21f522a0aed801df)
- Refactored async http client calls in web handlers. [`a4f2d4e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4f2d4e5626b83974350106fc7f97caa56ebeef2)
- Refactored show search list to not select shows already in library. [`5e05f9c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e05f9ce7ff2fb574e6d602457cbebb252701bfc)
- Resolved issues with unicode decoding output from version update commands. [`c894e74`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c894e74593d71486f84cfdb1422968be7cb7cbf6)
- Pre-Release v9.4.88.dev4 [`8b2b290`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8b2b290351a9f6794a28390d7d591387debf3be2)
- Pre-Release v9.4.88.dev6 [`aa389b1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aa389b1006a4816354c492fc23a6bd277dec6987)
- Pre-Release v9.4.88.dev5 [`60ad77f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/60ad77ff856c170f1211921b3409dbb221d73b8d)
- Resolved issues with sorting main show poster view. [`c71c5ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c71c5cefc9cdc668229257175c2ab816ecd8cf45)
- Pre-Release v9.4.88.dev3 [`2c95398`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2c9539800266a20fe69e5c111ac229288d416b8b)
- Pre-Release v9.4.88.dev2 [`4ba9839`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4ba9839f7ae543f1f616a9ea21af8da944b73b78)
- Release v9.4.88 [`a15394b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a15394bf1ea908d5b3d3b449a81ee874c644ed54)
- Merge tag '9.4.87' into develop [`4484245`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/44842450815de800de9e90fe983a75b330522dd9)
#### [9.4.87](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.86...9.4.87)
> 30 June 2019
- Refactored cache database last_search table provider column to be the [`b8d32c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8d32c76f4e9e858073b32ca6dc700bd96ec1080)
- Resolved yaml issue for CI/CD [`b4eb0e7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b4eb0e71ac8a12389ce285285ee51b73947a2743)
- Pre-Release v9.4.87.dev9 [`3c4a9b9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c4a9b9271e5422b2a6d229878e8ce92100b115b)
- Pre-Release v9.4.87.dev5 [`0a574b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a574b3635f6b490c4b664dc3bc908e239da1b4a)
- Pre-Release v9.4.87.dev4 [`352931e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/352931e93612cd0b5ad49102adb6cecd155d57de)
- Pre-Release v9.4.87.dev1 [`fda4adf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fda4adf7b754cd9c583e951ebe40927bf0f6c439)
- Release v9.4.87 [`0f183b7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0f183b7700e372470e5663679ae00efd1d7c09c0)
- Pre-Release v9.4.87.dev8 [`a4fc5c9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4fc5c9592bcc3494312356f299b322e67799fa9)
- Pre-Release v9.4.87.dev7 [`db4a94b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/db4a94b20afd37fe0695d82a80b21937c9a1d185)
- Pre-Release v9.4.87.dev6 [`2a6d3de`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2a6d3de117c84b2c33fe29935d3b172d64506a33)
- Pre-Release v9.4.87.dev3 [`25f4b66`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/25f4b661f420222883df42ffa711aa63646a7743)
- Pre-Release v9.4.87.dev2 [`d8ef193`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d8ef19390a193fc18a7d789a07378aad0cf2e822)
- Merge tag '9.4.86' into develop [`625ccfa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/625ccfa0bb8f3e23e1b736bccdedaeb7d7766ae7)
#### [9.4.86](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.85...9.4.86)
> 29 June 2019
- Release v9.4.86 [`5c877f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5c877f45fe86bbe7aaf275f043590b8c01f60699)
- Update readme.md [`81c32f3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/81c32f3b4320f6075fe89bfc4f3f538195fd84ca)
- Update readme.md [`4deb267`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4deb2671f0e7d6d9712289e3cc7306da608d15b4)
- Merge tag '9.4.85' into develop [`686783f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/686783f2190e5f5acd180c51d10dd8c7a379dbb9)
#### [9.4.85](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.84...9.4.85)
> 29 June 2019
- Migration from Python 2 to Python 3.7.x [`c8c1995`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c8c19951b34b3b30df9b07f92e90e4b0ff4280b6)
- Restructured web view folders and classes. [`1f9f2c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f9f2c413129513488aaca9e13c278d8be41a284)
- Migration from Python 2 to Python 3.7.x [`7f5696f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f5696f950ebb3f078ecc68c539f010b9f775fcd)
- Refactoring provider searches to search for one season/episode at a time, this will allow for better multi-thread handling of search queue items. [`81d9d7c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/81d9d7ce1b3659f5ac0841826e4f8c79a77ccfc9)
- Refactored file headers [`19708c3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/19708c3c956b3cd4f12a20894611d9212e75fb0a)
- Refactoring code for performance [`6f6e1db`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6f6e1db2508ebbd5897e31ec1980bc280ff2ecde)
- Refactoring post-processor code. [`4d9e816`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d9e816729b3ddb380512efd17c983011c42568e)
- Refactoring database calls to properly use session context. [`ced8924`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ced89247453064a7d4dd5d71098157a881816dd3)
- Refactored schedule calendar view. [`50275d8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/50275d8703ab4d199bc1585252081f086d920276)
- Refactoring database calls to properly use session context. [`5684a09`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5684a09482cfcb67e4ea62a1169ba5c411756724)
- Improved load time for main shows page by loading episodes into memory. [`f01d04b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f01d04b128fbf211ab3b56438d02684a9ca51857)
- Refactored `searchProviders` method [`7fa3757`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7fa3757e0e1e575bdac0d5b4f47dffc50e3f6b9f)
- Refactored History methods [`c31c7c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c31c7c4e83a2be7890a8d8602a5c2af0de0fe29c)
- Refactoring database calls to properly use session context. [`02d3bdc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/02d3bdc388a4b839b332261271eb4e871e4c92dc)
- Refactored core main helpers module. [`8d70465`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8d7046525b9f654eaf1fbfcf64614fa2cab715ce)
- Pre-Release v9.4.85.dev1 [`45c6de2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/45c6de2a2c6ca4072b0049413347463903e130ee)
- Refactored more database calls [`a5c700f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a5c700ffd2be7102c3b6502481bbd7b1ae9ff471)
- Refactoring database calls [`98df301`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/98df3016fec61fe3b178f002c1b2977ee576cd5f)
- Improved performance of loading main shows page and gather statistics. [`ca56cad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ca56cadee491dfa6b06750947f29def994104cbf)
- Fixed issue `install() got an unexpected keyword argument 'unicode'` [`8baf524`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8baf52440a720903575dae317da452d03671e1f5)
- Refactored configuration encryption routines [`762a0f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/762a0f10228330128e1b721a28dbda819028f3de)
- Refactoring post-processor to pass show and episode IDs instead of objects. [`c478beb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c478bebc3d3132f42604024fc4da0e6eb1f63c67)
- Enabled `autocommit` for database sessions. [`9ddf71a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9ddf71a71846ab85c6472fd10a92d115b2ad5b89)
- Refactored `find_search_results` function [`ac6ef8c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ac6ef8c150e3ef76efbc8160a630f88ad57d6da2)
- Refactoring of misc class names. [`b1e3ed9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b1e3ed92f4b08cb50746277586ac3410661277c0)
- Improved performance of loading main shows page by doing away with overall stats and moving stat gathering for shows to views. [`b1dd65f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b1dd65fa0977f7f221cf9ad49ec7c86c47cb933a)
- Working on fix for locked database issues [`c6f5543`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c6f5543332ea482b634ea2ff7a078df2f4c65ca8)
- Refactored search provider HDBits [`49b3286`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/49b32863378296074f1046b08f5862308f09cece)
- Refactored `show_names` module [`468638f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/468638fb9d9e45c744292bf0949e81544ee769de)
- Refactored database calls to be more multi-thread friendly. [`fc34dac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fc34daca5ce7e703d2a8809d4ca67fab982a9f10)
- Refactoring show object code [`b2d7407`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b2d7407d97f8dc6d3cb6a881a2f4da0d2b52275a)
- Removed remaining custom database functions no longer needed. [`9f4c8df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9f4c8df89f0cb3dead44340c400e183a386806b7)
- Fixed attribute issue for show object release groups [`45cdfe1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/45cdfe1d293c75fdc745f378e97b10e49f258ef5)
- Fixed issues were season packs and multi-ep search results would cause [`164b687`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/164b687cc9a309b2f123cf9f9a64d1d789567dda)
- Cleaned up search queue code. [`6af5a7d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6af5a7dee78f34bf2c7edae0db405923cccf75ec)
- Refactored schedule calendar view. [`6f3e014`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6f3e01496085f6045817d36c9eb32d6f6020fa48)
- Refactored encryption functions [`a13c1ef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a13c1efc62ca815feb14264bb44f2271570e582a)
- Refactored post-processor class code. [`8f8968b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8f8968bc9cf02548f70cb13f4256621483e5b934)
- Refactored database insert calls [`1bff88a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1bff88aa81e170039c394b6d794b965f7c49a5d1)
- Refactored how we delete database rows [`b65e3ac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b65e3acee78b2aa2c807ad4dc1cbe27adf13a98d)
- Refactored provider search to return single result, avoids multiple snatches. [`80cc2c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/80cc2c4835243655227181e651dff75933317556)
- Refactored tornado web handler to perform async calls [`c55f378`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c55f37875b5dfe29d0ff7ee3deb0571bc4fbe767)
- Refactored remaining database query calls [`da76cd1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/da76cd140835dd730b65aec0558b13296677c8dc)
- Refactoring database delete calls [`a495abb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a495abb035065877870b38488a4212f512b06156)
- Misc code refactors. [`e743c7e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e743c7ec3e26fa65830613da3de8ce305e90d2d6)
- Refactored database update calls [`2edaad7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2edaad7769558a484187283208745fee9e005e9a)
- Refactored show stat handling. [`a53079e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a53079ed0bcf736ccfb8389d2d28445253ec2330)
- Refactored scene numbering function conditionals [`87cabbd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/87cabbd1a721712aad2ae71f9fd77726c54e78f7)
- Resolved issues with show updates and refreshes related to database sessions. [`c6818d8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c6818d8b08ae882d3de48f94d2abb3954ddcb3cf)
- Refactored pip_path to pip3_path [`eed9186`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eed91867cf108b438b5f38806634ac7ccb2a9949)
- Working on fix for locked database issues [`2dd6518`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2dd6518872e4990b2b3147b9cc85c218ac923ec8)
- Fixed issue with main show page including downloaded specials in [`9906b49`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9906b4952a2506b609beb09910ca15304f0ef829)
- Fixed issue `name 'table' is not defined` [`3d8c877`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3d8c877684ca88e712b864e4cd47f80d11709050)
- Moved encryption startup routines to its own function call [`326cdd7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/326cdd71a33e96e3961e2a6408f571a92447182d)
- Fixed issue with calling backlog on newly added show with wanted episodes. [`e850bb0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e850bb0f99200337ed6409414701f0469e6c70e4)
- Fixed Zooqle torrent provider search issues. [`a2040ab`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a2040ab6a7463b1bb3be1213ccb4741b6ca4cc8a)
- Fixed issue with internal http client and auth [`c0cbb15`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c0cbb15f48bef05833360acff51df8a6e943c1f8)
- Refactored search code to account for season packs and multi-episode results when determining quality size constraints. [`30c9bda`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/30c9bdacfa45f609f40356bc2f19149a8084504e)
- Refactired database update calls [`87ae736`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/87ae7363b95779c8d2765e360a1dfd32f40cd541)
- Refactoring scene numbering functions. [`2803fa9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2803fa9f366b44cb3beaea92442a1e5dda92332b)
- Reverted scoped_session as it was removing session binds from models. [`d84f863`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d84f8634a05478089ed7738c93665044fb52ed71)
- Refactored `backlog_searcher` module [`f7cf3a1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f7cf3a184073ae5cfc06d0d16566fde3c58bc0dd)
- Misc code refactors for using show episode relationships [`b91e49c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b91e49c1450e7aa700a750872195229572b8e3ec)
- Refactored database migration code to handle unique constraint errors. [`7f15e46`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f15e46542fb7f0f99b9f9d1f9e6dbd9fe27cda9)
- Downgraded main database from version 13 to 12 to revert changes made to imdb_info and tv_shows tables. [`77a73fb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/77a73fb3b07656e1dce6d4a24dbc167bbe8a0312)
- Refactored search provider Zooqle [`17bb034`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/17bb034ff4408c2af1c750c53bd4315e5562e684)
- Refactored `daily_searcher` module [`c337738`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c33773841941732cd27c339e519b1f2cf4b2b281)
- Improved app performance in regards to startup time. [`ad47082`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ad4708281f9b5228abb5dad0c8bff24d3aa5e2d7)
- Fixed issue with post-processing manually and async. [`06aec91`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/06aec91d6bb9f2292aaf67508bf7a41b23a79d63)
- Refactored database update calls to merge object sessions before committing [`f05f45b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f05f45b220176e75348739bc288a25682b47badc)
- Refactored database update calls [`c382663`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c38266317b47e6c144cfbdc006b3a5a657263c8a)
- Refactored `set_sqlite_pragma` function. [`99b8bb8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/99b8bb820f00a2a439651ec13ca447232db31e7b)
- Refactored old code used for getting show episode images. [`1b78049`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1b780497928088764585c84383aec5a83eee6401)
- Refactored IMDbInfo table nullable columns allowance. [`b736150`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b73615052a90866b038a547e5b9f4c8f74c5a060)
- Refactored database update calls to grab session from object first that we want to update to use for committing the data [`7383dce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7383dce629513b5b5fe1ad0bc1465e4e8da22765)
- Refactored database update calls [`d55538a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d55538a86ffa9ed097f0ce4b789372c7448eae4c)
- Refactored `new_episode_finder` method [`f8ee032`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f8ee0322056eda71d7b2556131b9cba3e40bf976)
- Converted schedule and display show handlers to async. [`e34a1ed`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e34a1ed82c26b377ff416eecadd8ac551ccea5b0)
- Fixed 'InstrumentedList' object has no attribute 'all' [`0e375e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0e375e144d6d5ecc9e9762aa5256f0ef3b9be3c7)
- Refactored show queue to retrieve show objects from database via indexer_id attribute [`f571a00`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f571a00ae11f04f1c46b9175fba81d9ca06b1d1a)
- Refactored code to backup/restore `-shm` and `-wal` database files. [`0a963af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a963af2981459660c14d2ea5d8f4e0aa09a5333)
- Fixed issue with History table migrations. [`69abaf4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/69abaf43ebaba9f2f5dbdbbbe5ef4576627918de)
- Fixed issue with displaying show stats when adding or removing a show. [`bbfd1ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bbfd1cea1e4aa6e14394352d38b858a33d9c6dc2)
- Fixed Quicksearch, was incorrectly encoding data. [`1f9477e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f9477e894502fde83da0ba8d4f0a62bba4e6ea1)
- Refactored main shows page to not include specials or unaired in totals. [`4b8e9f0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4b8e9f03c0f4e47236ca8ec947e22659b6bc017e)
- Fixed issues with manual searches, added session decorator to snatch episode function. [`225936a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/225936aeaf3b7d64b44816a0915a7c0b697ef9cc)
- Fixed issue with forcing backlogs and finding nothing. [`356ab93`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/356ab93562b8202aa031a83b75ec45db219c8998)
- Working on fix for locked database issues [`521828f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/521828f94c094b8e855bedfb80c47fc3e05c27b3)
- Misc cleanup of database models [`cc98260`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cc98260942c8b402319d65bdd59cb0540e86b855)
- Refactored progress-bar for poster view. [`f75ab47`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f75ab4795ef2eb60d104ac2c9acc2fdd132d72c8)
- Fixed issue where scene_season, scene_episode, and scene_absolute_number got reset to zero if not found on XEM, caused search issues. [`2559549`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/255954995c836d748c07727e47eb89864cc7a378)
- Fixed issue where main show page will show duplicate show entries when adding a new show. [`c76465f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c76465fc93ed8c8fddde403c9da08469c0281cf5)
- Fixed issue with getting IMDb info [`5b74195`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5b741954a50908ed7c8abca4331be4b7a0bf04e0)
- Refactored `BacklogQueueItem` [`f52da13`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f52da1338c669c1f1e2a82f03a2afc117bb4dd7e)
- Fixed issue with backlog searches not working due to async not being properly implemented on queue items [`07dc6b4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/07dc6b47f05bd9cc209295d67f0e16f246b06db9)
- Fixed issue with unprocessed videos being skipped due to being processed. [`52691bd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/52691bd6a55704e052ae3e839fd6f93628f3f62a)
- Fixed issue with adding existing shows and being unable to parse a filename into a show object. [`16d0db4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/16d0db46e116fa5af2a0622d147f08b4d912d876)
- Refactored `set_sqlite_pragma` function. [`85e8749`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/85e874939de69c3df9dd7e874becb98f77665cf6)
- Refactored remaining incorrect database calls for CacheDB. [`6e27416`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6e274160ff90a411fcf6d94c9e6a6f17d62e3895)
- Fixed remaining calls to variable `current_item` [`d30471a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d30471a50e6b6062619b2f112c2b58e14290ba93)
- Fixed a typo [`f3877e7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f3877e792685e7ff186173a2f4773a8bde780a36)
- Fixed issue with creating processed marker files. [`c7e61d6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c7e61d642886a912a63a3091d08e2f88d249343c)
- Refactored `run_task` function to not be async, returns future that can be awaited or fired and forgotten. [`f8b9e2d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f8b9e2df234271998b038715bc141aa05ec5a64b)
- Fixed issue with show name not being displayed correctly when a show is being added to the database on main show display page. [`47e5445`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/47e5445f74be75493659435f7c6775ddb62c0a5d)
- Refactored xem_refresh database update call [`264d5c8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/264d5c80e9a23e1fa549a6ea5a442fd95b5e39a3)
- Fixed issue with adding duplicate provider results to cache. [`cef3044`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cef30445213a0381e0d1c90eca6a5311cd0d7623)
- Refactored misc errors to warnings. [`3832745`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3832745f4428bcf58c65aed8357046ce6283d26d)
- Fixed issue with displaying existing shows from multiple root directories. [`b1e7d1d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b1e7d1d1923b6af6f7d3957bcffe6a1cbf9f23cf)
- Fixed issue with slack and binary messages [`baf2f48`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/baf2f48aeeef3231e4a8496d98187c2674762a31)
- Fixed issue with history of snatched episodes not having their statuses updated after being downloaded and post-processed. [`a2d0eb7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a2d0eb747fc97a573b4efc83543852f4f1bea0ce)
- Fixed show display page to sort drop-down of shows non-case-sensitive [`fea454a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fea454aad1c3196df74614be83450715fc0d52a3)
- Fixed issues with parsing xml data for Plex and NZB [`516bec5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/516bec5a251ec7cca98048a07524fd418e851c86)
- Refactored configuration encryption routines [`124ce33`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/124ce33cf6370c7c240bd9777856ff81187534da)
- Fixed issue with initial setting of app_id [`9d884af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9d884afbae19e8e8518c9e0ffaee842176d98a2f)
- Refactored remaining database calls using old-style dictionary calls [`4d7d73e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d7d73e422e2590e0e2d71717c82eb9922164399)
- Refactored main layout submenu creation to honor required setting [`3382e14`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3382e1427fc1613b8510a1d2a8894ff2c3b006c0)
- Python 2 to 3 database migration happens against files in root of data directory instead of seperate migration folder. [`0e1b42e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0e1b42e198bc1021bea0020bb2f1188f70edca78)
- Pre-Release v9.4.85.dev19 [`ae7eff4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ae7eff421cf90e01cbd752c14c6d92f160cb2e74)
- Refactored episode properties to not include specials. [`37f7632`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/37f7632d50544645e64660063dbac83834be258b)
- Fixed select issue for display show drop down. [`42607c3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/42607c3b1aa4fac277470c748f4455de9222cc8e)
- Fixed issues with version updating. [`b69acd0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b69acd091650424d5e97ac265337ffa4817bb7ed)
- Refactored database engine to use a QueuePool with a size of 100 connections. [`ab3d032`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ab3d032de14f8585b86b3fed3da9a39077a02194)
- Fixed issue with clearing errors and warnings [`61cce7c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/61cce7cde91518f1f582c4d7e08143c9af1d5e96)
- Fixed issue with show not being added when trying to add show via queue. [`77ac496`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/77ac496ba50b590c35b5d541f9a822de66a120fd)
- Updated primary keys for quicksearch database tables [`78fa24f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/78fa24f70e6609e4b0612519664a82a78b9bed76)
- Fixed Mako error for status page [`caaf36a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/caaf36a3eacc9f08c7190c45e2aefa09fd6310fa)
- Fixed issue with black and white lists [`a4929e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4929e4291fa17d428315994aa1a3de306ad1ec5)
- Refactored variable to function call. [`289685b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/289685be2f0e9d114e64ccbc5b254cdb6d150122)
- Refactored history lookup to return first result instead of only trying to return one or none [`1dc9ad9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1dc9ad934598ead1472c3646f9b87683b1cacabe)
- Fixed issue with loading episode details from .nfo file for multi-episodes. [`255da20`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/255da20e83e4761234f1ea7ba31bf1b570bca286)
- Refactored history clear and trim web handlers to be async. [`f3e2f64`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f3e2f64098d1ca4311ce03d0d41e2a64a2b12712)
- Made minor adjustments to queue [`fbe61c6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fbe61c6d691646f632de99c4812c98f6b165d4b8)
- Fixed displaying queue priorities from server status page [`ff4ea98`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ff4ea982ad505f622c16d5f9950cf5e060f14fc2)
- Refactored backup/restore functions to include public encryption key [`2fccd96`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2fccd962274ed82cca9129fe5ccc039e1f565dfe)
- Pre-Release v9.4.85.dev23 [`eef0ad4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eef0ad4b26d9736df2d737833d92a667333d3bef)
- Pre-Release v9.4.85.dev21 [`7d0b6b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7d0b6b2a31cc7a39ef4d0740f0377263fa31eb55)
- Fixed issue with searches and picking best results when multiple results presented. [`3867759`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/38677592b333a806dfa5e7fe7f15e768adb3b786)
- Refactored database delete function to check count of query results before attempting delete to avoid errors [`7b833ac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b833ac6d88352d0aafffa826a71f225477108ed)
- Fixed issue with calling backlog on newly added show with wanted episodes. [`29b7ce4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/29b7ce4cd7559a7c1531606e2733b57b908c249c)
- Pre-Release v9.4.85.dev10 [`4efd8a0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4efd8a0b9c766f409e9103887279c1616dbe58a1)
- Fixed source commit variable to point to correct enviro var. [`0aae828`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0aae828af6ef762ead68d3660c9e11c5c8b70d2a)
- Pre-Release v9.4.85.dev6 [`4c7abdc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4c7abdcb3212d6c4792c883c208ed246011ca030)
- Fixed issue `OverflowError: date value out of range` [`3d9725a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3d9725a5157da65d642d0fc050688c25d4f1d0bd)
- Fixed a issue with relationships for tv shows and episodes [`a305c92`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a305c92b5be3ca78ae1c184046a29f8c6dedeec6)
- Fixed issue with polling for episode search status from scheduler page when no show ID is provided. [`80ebdad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/80ebdad5e385a2341bdcb379cac815c4d2937998)
- Fixed issue with automatic post-processing [`aca0067`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aca0067d8b974c343b4a35fbb31841c81b2ca241)
- Fixed issue with queue and `max_queue_workers` variable [`8917d88`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8917d8874c0de12da945462473448a7a2635d473)
- Fixed missing handler for post-processing view [`2ac7b86`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2ac7b86d4cadc2397b4676d174cfb53a953a25fb)
- Refactored backup and restore functions to include `privatekey.pem` [`208a6d0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/208a6d03e9a9477698c41f5e1e942dfe87c2363f)
- Fixed typo for restore function [`622650a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/622650abe5f8b1e4c9e5fc99d6361dd238f2557a)
- Pre-Release v9.4.85.dev37 [`859f7d3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/859f7d3e2f8cc01533676c7b75124dedeaaf26cd)
- Pre-Release v9.4.85.dev36 [`3bb44d0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3bb44d02281d62efa72fc98298e11c5cf4edea33)
- Pre-Release v9.4.85.dev32 [`d37b9d8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d37b9d8033a68f88a2978f9c7f17f53b239041fc)
- Pre-Release v9.4.85.dev30 [`a75533a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a75533a33d5b2c4e63fb31d1b61536ef22197cc8)
- Pre-Release v9.4.85.dev17 [`0d74c97`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0d74c97948179be1d67cca74eae02462f37d2188)
- Pre-Release v9.4.85.dev4 [`acb8383`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/acb838359585b0d80c8d611b5cfc1a17d9887b8a)
- Pre-Release v9.4.85.dev2 [`d9cccea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d9cccea9be1f40422a8b02b86212e070982d5125)
- Fixed issue `Missing argument pid` [`eea340c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eea340c9522dd92fb3eaaccc1ebf0d8b5ba47c2c)
- Fixed web call to force daily searches. [`887cb3a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/887cb3a8bd681aae08f833a7cb006917faedd0c7)
- Pre-Release v9.4.85.dev35 [`b7bc6f3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b7bc6f3ee451548abbad82bf4d5826ef73f1201a)
- Pre-Release v9.4.85.dev31 [`d50d140`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d50d1406ce04b18b865944d1f18b0be3ad2b6006)
- Pre-Release v9.4.85.dev29 [`242607a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/242607a985743959caadb9f5fbad9faebe629563)
- Pre-Release v9.4.85.dev28 [`f3b429a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f3b429ade7d0526b9facc5ddc9b97a469f5b0f1f)
- Pre-Release v9.4.85.dev27 [`8545559`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/85455596c5820c1a782921407af39db97895f736)
- Pre-Release v9.4.85.dev26 [`71c7f47`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/71c7f470e5e19ed3525df29a4612f60b6fe6759d)
- Pre-Release v9.4.85.dev25 [`0fe4cdd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0fe4cdd0455f80914972079cc6f0f115fdc6822e)
- Pre-Release v9.4.85.dev24 [`7a7446a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7a7446af4bd4ee5fccf300d374559c9346815046)
- Pre-Release v9.4.85.dev22 [`a5032f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a5032f12472445146d901c36aabe5418d740761e)
- Pre-Release v9.4.85.dev20 [`8403749`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/840374995c6545c16e096b6d1d214ba15ab9009d)
- Pre-Release v9.4.85.dev18 [`fc59ac3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fc59ac305095b37b516314cf29de17f2892d19f1)
- Pre-Release v9.4.85.dev16 [`5ed3462`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ed3462f803da9a487602834ba192b178c1e2c34)
- Pre-Release v9.4.85.dev15 [`1e38c3c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1e38c3c0ac2b6fc4bb7412b9d5d92dbedcf24ee0)
- Pre-Release v9.4.85.dev14 [`a229286`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a22928603bad513405d01b61bb02ec0ca53d8ebe)
- Pre-Release v9.4.85.dev13 [`d8b37b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d8b37b3538a08a4a5d52c92c7febf0ebe7e74194)
- Fixed episode total to not include specials. [`5478146`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/547814611e743a331fde0dad02dcb1e75de88725)
- Pre-Release v9.4.85.dev12 [`c8e8d12`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c8e8d1279a568c93403da7cad978884fd27f1ce8)
- Pre-Release v9.4.85.dev11 [`fb2f3b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fb2f3b2f81b752a5198deda873ce7323ba226e17)
- Pre-Release v9.4.85.dev9 [`2c370dd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2c370dde3e70965ce4edd52daecd62c8e84344b5)
- Pre-Release v9.4.85.dev8 [`ed7d5e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ed7d5e1468a84bdeeffb8760e977a878338d654f)
- Updated YGG torrent provider URL. [`0f90596`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0f90596670720268939310f74a9914ede86aa5ab)
- Pre-Release v9.4.85.dev7 [`20831e8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/20831e8bca8de07dd51d8a6f8ad267ed07ce5d90)
- Pre-Release v9.4.85.dev5 [`9c4bfe1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9c4bfe19bebca1f629f39d7142032302fc093550)
- Pre-Release v9.4.85.dev3 [`9e93282`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e932820f2cb98045cbf9dc92bb9e2ac995fea1a)
- Fixed issue with daily and backlog searches not running. [`271a443`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/271a443f94bde7db70dccf9bd9923dd46adb4139)
- Updated requirements [`410b5fd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/410b5fdddbf69410bbc4025af3debd5b36e30823)
- Fixed issue with viewing logs and max lines [`a4ee42f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4ee42fd7f791c37068bc1c4fb28b1764028c7ba)
- Fixed issue with looking up show in database using string search terms. [`2eb5847`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2eb58478ceb0c6f1525afed34c5311595bdc06d5)
- Refactored backlog and daily log messages to indicate number of days its searching for. [`3c3aed5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c3aed5d3f7167a8288c50a95cf4e76550153572)
- Fixed issue with loading of imdb_info attribute for shows [`d93dc9f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d93dc9f624da214e45d4801562b8bc0db39e504c)
- Fixed more logic with `max_queue_workers` [`a4b1b61`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4b1b6188b26aae82f41a3c8122b10da90e8f060)
- Moved call to register app-id [`555d960`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/555d9603ac48c4ab5fd2c06c7d79b1fa20326984)
- Encrypt config only if able to save encryption key [`78f5288`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/78f5288090b095c4c49f586a33b7d64f43b8172c)
- Release v9.4.85 [`1ca6bcd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1ca6bcdec27660c6a0436fca8ef087ded58479ce)
- Pre-Release v9.4.85.dev34 [`17f4e24`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/17f4e245c9d7225d3d87f8804644d98e219ba09f)
- Pre-Release v9.4.85.dev33 [`13c6d5e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/13c6d5e05eb7c9d8c6f25449f302dc124e78f98b)
- Refactoring post-processor to pass show and episode IDs instead of objects. [`52147ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/52147ba694bc76997eda067ab8067015ceefda05)
- Removed un-required sleep for post-processor [`a2fb2db`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a2fb2db61c6dcef98d6a57c72e8f6f5a58489303)
- Fixed typo in CI/CD script. [`c3f6024`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c3f6024329bda0cccc8ba57cc9f32e7f42e35bb2)
- Downgraded main database from version 13 to 12 to revert changes made to imdb_info and tv_shows tables. [`0cf4b20`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0cf4b20fdeccdab95724e7a574da086e1db652bc)
- Fixed issue `run_in_executor() got an unexpected keyword argument 'webui'` [`57e5d92`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/57e5d92bfb57d46b4e141995026a2fd8b7887e0c)
- Refactored code to backup/restore `-shm` and `-wal` database files. [`302fb73`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/302fb737c5946c5f9c949f9265294a8973bd955d)
- Removed ajaxsearch init from schedule core js handler [`11903dd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/11903dd263775f34d5145396250fbf02246dcd7d)
- Removed ajaxsearch init from schedule core js handler [`fb7f665`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fb7f6659bd82936b9f25714df73af7c01874f23d)
- Misc typo [`d8ba166`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d8ba1666c3cc30c5a90741d59bd2d1d13ae3bfbb)
- Removed committing to add and delete database methods. [`5f870d9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5f870d9ba4755aeed6a7de54edf609d4299b654b)
- Fixed issue with trimming history. [`4375dff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4375dffcc86a8f572d6d5c547ded9d292cd32c6b)
- Update __init__.py [`6b8ef37`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6b8ef374b450f9916eaed376583a21981b0662f1)
- Fixed issue with drop-down show list for display show page [`0fd669b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0fd669baae995a3115dce98a3066a6c1c174215e)
- Changed logic for queue and `max_queue_workers` [`5b01682`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5b01682461e64aefa9da922c772403b3dda0b657)
- Fixed issue with queue and `max_queue_workers` variable [`506ed4c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/506ed4c38a4e20a0208892524061a53481190daf)
- Fixed `In Progress` for show queue status in Mako code [`48438eb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/48438eb666f10c16e70b69e37e9db2ac5a6bc875)
- Fixed missing params from get method for post processing handler [`afece73`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/afece7307c69fa82a8d999c2c7af2026c5e1f7f1)
- Refactored queue to process all items that are queued at once instead of one at a time. [`2ce606e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2ce606eb95d0c22ac67f975b6cb6ac41b017af1b)
- Fixed issue with mapping when called by reduce, wrapped in list call. [`aaefbb4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aaefbb428a20ec517586020ce54523336407a672)
- Fixed `can't have unbuffered text I/O` value error [`a228f02`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a228f02ccc26999b4b7f093b15f69f6c698babee)
- Refactored public encryption key to be saved only after private key is saved [`5d65e31`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5d65e31cb35ec0382e4367296ebaab48316c57a7)
- Updated version to 9.5.1 [`8f59e6d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8f59e6dc25ad7838b758ab560bbeac00663e32b1)
- Refactored database update calls [`412de15`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/412de15dcf3b7ebce4c687691f780b708c6c7171)
- Updated python-keycloak-client to 0.2.2 [`c7a4409`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c7a4409b70d9aae1f118bdda2609d83b09cade4f)
- Fixed status page to display show queue item progress correctly [`faa271c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/faa271c4e3b6e5fd3732ba4dd3d78884496b0214)
#### [9.4.84](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.83...9.4.84)
> 6 April 2019
- Pre-Release v9.4.84.dev2 [`611cb16`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/611cb16d69ed6068e75b3d230197b93f334bdb32)
- Release v9.4.84 [`c41a995`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c41a995d1618af450cbc8a3d4d36f6e367fa46e1)
- Removed py-unrar from requirements [`96aab9c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/96aab9ca4dbb0545147b3436324e3615a9b3be74)
- Merge tag '9.4.83' into develop [`fb6f06f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fb6f06f2c9cb2dd2f61ca736dbcfed0edd1f7b87)
#### [9.4.83](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.82...9.4.83)
> 9 March 2019
- Release v9.4.83 [`d8b8087`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d8b8087e86d8ba04b2de809f7970c3e408c23f61)
- Fixed issues with source updates. [`471976b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/471976ba7c7c1fb7b4b6e925beb184caf9f56d7b)
- Merge tag '9.4.82' into develop [`5b429fc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5b429fc1871da1cf566760e8393787cdc8169321)
#### [9.4.82](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.81...9.4.82)
> 6 March 2019
- Release v9.4.82 [`ee7439e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ee7439e9ed2faf634119fab6eff24b362f2033f6)
- Merge tag '9.4.81' into develop [`57650a0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/57650a0236f438502db24c12756dc6cb4983596f)
#### [9.4.81](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.80...9.4.81)
> 6 March 2019
- Release v9.4.81 [`8a67674`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a67674262155f52a63973c374e63b433041bef0)
- Merge tag '9.4.80' into develop [`4662673`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4662673088f6b993c58c9d567adbaaea501bb723)
#### [9.4.80](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.79...9.4.80)
> 5 March 2019
- Release v9.4.80 [`6de5fa5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6de5fa566c1456866b28b11ed254471c443b4b14)
- Fixed saving of provider settings so that booleans are saved as integers [`43baedf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/43baedf8e0d91ee7f4f6bda98e6dec4a9ccac554)
- Merge tag '9.4.79' into develop [`7fe3583`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7fe3583471a3e6738f838cb7cb834af89cdae8c3)
#### [9.4.79](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.78...9.4.79)
> 4 March 2019
- Release v9.4.79 [`4f0d739`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4f0d739a2a935b9ab30aa1bc9402f9df68b18184)
- Merge tag '9.4.78' into develop [`78e1194`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/78e11941211fccaf18ac06682fc2208eb9de7b52)
#### [9.4.78](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.77...9.4.78)
> 4 March 2019
- Release v9.4.78 [`74f6d46`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/74f6d4603df82d7570874b282330a00415319721)
- Cleaned up backup and restore functions for database. [`3151280`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3151280c7ef0bead219c4ba8d8497607f26a1f2f)
- Merge tag '9.4.77' into develop [`01dfecd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/01dfecd8c51df568d9372f0240422be24c3a6e43)
#### [9.4.77](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.76...9.4.77)
> 24 February 2019
- Release v9.4.77 [`a72ca25`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a72ca25f7e2d6a69ee61b82d67782a0db15200b6)
- Merge tag '9.4.76' into develop [`377a573`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/377a57341a4ba374c9ee5c5d264df6f6b5981901)
#### [9.4.76](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.75...9.4.76)
> 24 February 2019
- Release v9.4.76 [`e0f2db6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0f2db68575041a45ea428afea004546267db62a)
- Merge tag '9.4.75' into develop [`897dea8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/897dea8e160aa2f982ec98890d01a0d96a4c20a5)
#### [9.4.75](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.74...9.4.75)
> 24 February 2019
- Release v9.4.75 [`abe73d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/abe73d7802020778aa01226480f6ae46fa00278a)
- Fixed issue with scene exceptions not being retrieved. [`f4b1e65`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f4b1e65d9f8dffe31d6a152c3f7ab125c175098d)
- Merge tag '9.4.74' into develop [`9b5dd59`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9b5dd59468796397c3f61af6893b23635030dfeb)
#### [9.4.74](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.73...9.4.74)
> 24 February 2019
- Pre-Release v9.4.74.dev1 [`1ebefb4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1ebefb42e3a5753c9e44126fefe847ab24957d83)
- Release v9.4.74 [`78d6b6e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/78d6b6ecc45b7bf64c3962936ef19496ac1b0037)
- Pre-Release v9.4.74.dev2 [`90fa33d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90fa33d218235bb09a2df4f886a4233779d1ab4d)
- Fixed issue with default add show options and add show year feature. [`b690738`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b6907389629b0891a73229c54811a28aed670740)
- Merge tag '9.4.73' into develop [`045620b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/045620bfc7e85a89d436d636629d9d4595389a7a)
#### [9.4.73](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.72...9.4.73)
> 24 February 2019
- Release v9.4.73 [`ffd8fa4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ffd8fa4791a0bb0d75d5a0419f550e7d93faa3b8)
- Merge tag '9.4.72' into develop [`337acf9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/337acf90960c8a2806426c7ad8e693256514f0f8)
#### [9.4.72](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.71...9.4.72)
> 24 February 2019
- Release v9.4.72 [`47572b6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/47572b673012e75705b9e7dcec6edac150a3c8ce)
- Merge tag '9.4.71' into develop [`7ef8aed`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7ef8aedc97ab3ff087062e29a40795594f5bebfd)
#### [9.4.71](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.70...9.4.71)
> 23 February 2019
- Release v9.4.71 [`b86d9d2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b86d9d2eda05f4edae03bb2ff76c625085b5bc0a)
- Merge tag '9.4.70' into develop [`dd79285`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dd79285cedd8065a626f06e4d114f4515f22f798)
#### [9.4.70](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.69...9.4.70)
> 23 February 2019
- Release v9.4.70 [`ea526d2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ea526d22fee7dc3b31256741ade628576084d048)
- Pre-Release v9.4.70.dev1 [`2e4fa85`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2e4fa859c8cc6fb77cddd04135d1e1c32c7ffd3c)
- Merge tag '9.4.69' into develop [`df9fe01`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/df9fe01ea0b5b46d112b1a78ed8cb8151c30ebcb)
#### [9.4.69](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.68...9.4.69)
> 23 February 2019
- Pre-Release v9.4.69.dev1 [`2f89453`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f89453ad18ae9bbf5008dd875ff41799b9a82c9)
- Release v9.4.69 [`502eb01`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/502eb01636c0bef2bfd1ea73f8635525e1f68884)
- Don't attempt daily or backlog searches if nothing to search for. [`ffa69b5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ffa69b5186fb2de9c996a2a057c80d3b38fcc86c)
- Merge tag '9.4.68' into develop [`954c634`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/954c63461afe5caaf7bf036135868d9f0cb8772b)
#### [9.4.68](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.66...9.4.68)
> 23 February 2019
- Release v9.4.67 [`3f6df12`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3f6df121d9a4e7dd708dbfadb87925ca9e3ecf4d)
- Release v9.4.68 [`c3441ed`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c3441ed155c761f553d9f8772de514bad7d66378)
- Merge tag '9.4.66' into develop [`9a730c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9a730c4d3854bc4eb25b7a5e722daac8eda40d22)
#### [9.4.66](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.65...9.4.66)
> 23 February 2019
- Release v9.4.66 [`9c78d0b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9c78d0b1c6acd2edab8016f5120069e97f17fb5d)
- Merge tag '9.4.65' into develop [`4acabb9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4acabb945597fde0d5d4f65c14eba0a3580b39f4)
#### [9.4.65](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.63...9.4.65)
> 23 February 2019
- Release v9.4.64 [`15ffdce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15ffdce8031c36b881a477041865040a458b09ed)
- Release v9.4.65 [`8275fd1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8275fd1ebaf370c24b6af9bfde7a7078475a29f1)
- Merge tag '9.4.63' into develop [`caf00c9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/caf00c99483ba378406956b1b412ccc7cd789b30)
#### [9.4.63](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.62...9.4.63)
> 23 February 2019
- Release v9.4.63 [`33a4acc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/33a4acc8ecc4b409b51cf3c5927d4470f7cfc378)
- Merge tag '9.4.62' into develop [`e4c0f75`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e4c0f750ab564ae2fb21116d160c7f016dfaf618)
#### [9.4.62](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.61...9.4.62)
> 23 February 2019
- Pre-Release v9.4.62.dev1 [`04b3d37`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/04b3d3784b5ba3642c02b6153623ab59922541bd)
- Release v9.4.62 [`1e6bcf9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1e6bcf9746d276f7c9d56911820940be2900573c)
- Release v9.4.62 [`e648c9e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e648c9e8b84ef2c7baf0fc34a6887125188e9655)
- Merge tag '9.4.61' into develop [`1207d88`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1207d889dedb8f60c58a0020b51224443340e9b1)
#### [9.4.61](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.59...9.4.61)
> 20 February 2019
- Release v9.4.60 [`9467ad1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9467ad108a5173703d2ef5ac32190d7b59e1366b)
- Release v9.4.61 [`724fc6b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/724fc6ba708a19e14e573d80d38b5f2bbb6dba38)
- Only shows in library are cached. [`e9b99d5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e9b99d5b057463a8a4796e96e79cd4de5406d964)
- Merge tag '9.4.59' into develop [`049deab`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/049deab420285b2f545a5c747dde82f9b724b02b)
#### [9.4.59](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.58...9.4.59)
> 17 February 2019
- Pre-Release v9.4.59.dev1 [`0a29873`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a29873ba114f3e2ac29432f95619438fd0d9b93)
- Release v9.4.59 [`13659fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/13659fef5b7825b13824229cd553fc20e456aaca)
- Pre-Release v9.4.59.dev3 [`01ad8b6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/01ad8b6645d86bfaea24818f4537a1b210a0b063)
- Only update indexer details for shows when performing show updates on shows marked as updated on indexer, full updates performed every 7 days. [`141d1ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/141d1ce7a3addfd276b2a1e839048b613673b86f)
- Fixed issue with "unable to verify the download url" [`d41e525`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d41e5256e38eda52d2a7fde890eeae745959c775)
- Removed redundant automatic show refreshes as these happen during automatic show updates [`3af8cda`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3af8cda0fc6c253580d77e0b9c3edc6eeb3b9c9c)
- Merge tag '9.4.58' into develop [`dd0f62c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dd0f62c84171d40926ec4c126d291e5b74337aa9)
#### [9.4.58](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.57...9.4.58)
> 22 January 2019
- Pre-Release v9.4.58.dev1 [`c128f16`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c128f166eefc7733dabc98e340f8017a6b9345e9)
- Release v9.4.58 [`9a10462`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9a10462301ee20f3b9d6a0f477f5569905db2bb3)
- Merge tag '9.4.57' into develop [`5fca1bf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5fca1bf5485824ecf352f9d1f86b0a26e0163779)
#### [9.4.57](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.56...9.4.57)
> 21 January 2019
- Release v9.4.57 [`8913178`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/89131788d9bc994532f2d290941d8d5028665896)
- Fixed auth issue causing redirect to home page every 5 minutes. [`ae5c478`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ae5c4788465bad410d7f9d55749d42d21a04d8ab)
- Updated Dockerfile. [`f065a3e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f065a3e32e14c367f00795726798a30d21a84e48)
- Merge tag '9.4.56' into develop [`aaec028`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aaec028645747e043e2aba047ab07e775e1f6eaa)
#### [9.4.56](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.55...9.4.56)
> 20 January 2019
- Refactored processed marker code [`6e96928`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6e96928bf650de4e567ef03f219857e6bf9de970)
- Pre-Release v9.4.56.dev3 [`79db85e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/79db85e8a16013bccb9535051b5b86676a4217c4)
- Pre-Release v9.4.56.dev2 [`8087452`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8087452142626d3a8f99de3b8fc5d3ac25789456)
- Pre-Release v9.4.56.dev1 [`65c449e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/65c449e5f5fe948dad98d9086297de6194bf6572)
- Release v9.4.56 [`b2b9f0d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b2b9f0d37dc50598eb4ff0cf94c70c9de8e75c4c)
- Pre-Release v9.4.56.dev5 [`25bcd7f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/25bcd7fb8499aafa535aa8b5631ebf37d7d37be2)
- Pre-Release v9.4.56.dev4 [`14f8938`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/14f8938b1010598d8eeff5e2bda480faf084d388)
- Update .gitlab-ci.yml [`3f76554`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3f765548a0e64b9f7951a42d0ada39d647cec9af)
- Update .gitlab-ci.yml [`831f077`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/831f077c87d75152bf310661e8fc6c375b3508c0)
- Reverted usage of `next` to `continue` in mako views [`1d012df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1d012df56bec0bb8221b6994e9f593a32c25b69f)
- Fixed typo in show schedule page, double web roots. [`a2596ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a2596ce07e09bfa12f435b7dc0de182787628adb)
- Update Dockerfile [`60c219a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/60c219a511af217fa586ba76dd14fb3ae8686f04)
- Update .gitlab-ci.yml [`7c6290c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7c6290cb526cbae000757b670d25a8478dc0333b)
- Building of DEV docker images now implemented [`a26f1df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a26f1df52da1bf106ecd6f87bc0dd1e656b47f41)
- Update .gitlab-ci.yml [`d326930`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d326930d1c36e02d1cf16a80fd9b5d811b7e12a8)
- Update .gitlab-ci.yml [`bf51f72`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bf51f728fddc2b71fe500197e13ae59a740ba1e5)
- Update .gitlab-ci.yml [`560357a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/560357a4d1204bc743e1b2f1a6a0e7e00a6cbaee)
- Update .gitlab-ci.yml [`2543e7c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2543e7ce2463e5cab616f146ae2a3efa272ae41d)
- Update Dockerfile [`74f25eb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/74f25ebf02414fdd2ea2748ecf56c06ec3dfcdec)
- Update Dockerfile [`c27cdf7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c27cdf73c1c94c4711f6bbd2ae154bd4d39be7e6)
- Update .gitlab-ci.yml [`68a9176`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/68a91769630161e2171cc53e98341d3572e9b599)
- Update Dockerfile [`5fcae91`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5fcae915c1f6d07c6f35eece08aa7d950cc9d533)
- Merge tag '9.4.55' into develop [`568a883`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/568a8833b5a0cfd721d7724aefcc906117ad3d55)
#### [9.4.55](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.54...9.4.55)
> 16 December 2018
- Release v9.4.55 [`3865c15`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3865c15e951608ea2036a2207335bd4b4ce8ea68)
- Moved columns button in display show view. [`164c01f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/164c01ff93ee080a7f24f82f504e427a941d8278)
- Merge tag '9.4.54' into develop [`eb6a6f8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eb6a6f8c7ec5bd112e73908872b44ecb7b37b83c)
#### [9.4.54](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.53...9.4.54)
> 16 December 2018
- Release v9.4.54 [`5e64b16`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e64b164f0024ca833c652a65be1ec97be49f100)
- Refactored display show view. [`76c2230`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/76c2230ca60ac3f8191592818d28ab06defd6f5b)
- Merge tag '9.4.53' into develop [`e54f2cc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e54f2cc2457f45e1fb7efe83b54d1456daa35556)
#### [9.4.53](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.52...9.4.53)
> 10 December 2018
- Release v9.4.53 [`91bc24c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/91bc24cb4bb32e78779541370b61bad59a688bd5)
- Merge tag '9.4.52' into develop [`571aae1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/571aae1ae31f67a9be2d1edeb20795c7bf60c0cf)
#### [9.4.52](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.51...9.4.52)
> 9 December 2018
- Release v9.4.52 [`7dd5263`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7dd5263954634a499b9fd8fe460654c6ea04c7fb)
- Fixed issues with display show poster positioning [`c65074d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c65074d9adfde9a91dc9dc84b92501691da522e8)
- Merge tag '9.4.51' into develop [`490fb47`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/490fb47c52404c311f4aa3bf00d063f4ae434edd)
#### [9.4.51](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.50...9.4.51)
> 9 December 2018
- Release v9.4.51 [`65486af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/65486af604d684f1dc77b4554a442a3e19daab0f)
- Merge tag '9.4.50' into develop [`9cd3f0a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9cd3f0a8ae315ffd94228b5bc801a1804454a938)
#### [9.4.50](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.49...9.4.50)
> 9 December 2018
- Release v9.4.50 [`8bfcd44`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8bfcd4453c18f0de02c3ec361b00f8e68a0f5866)
- Refactored display show view header [`60cabed`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/60cabede594dc8434b2146a483df02845ca6e3d4)
- Refactored menu icons to be fixed-width [`2d4e3dc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2d4e3dcf576a531ff62ffbc9b9b35cebda0eb353)
- Refactoed display show view [`b3b4d7a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b3b4d7a8ff603ca847be49cacc80d8097bae1eb9)
- Refactored quicksearch menu [`c97cce5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c97cce59de59ddd3610e0541b07f2e42ac5ebe27)
- Merge tag '9.4.49' into develop [`e5cadea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e5cadea8b9fd783b9d09cf36c0a4f5c4d14bedc2)
#### [9.4.49](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.48...9.4.49)
> 8 December 2018
- Release v9.4.49 [`c1aed13`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c1aed13381c1ae4c965917657d4c42d6c31a1ebf)
- Merge tag '9.4.48' into develop [`8e662ef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8e662ef3c1e90311b75658d1e06f4c99087762f0)
#### [9.4.48](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.47...9.4.48)
> 4 December 2018
- Pre-Release v9.4.48.dev9 [`b55a806`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b55a8060f0a542a84c5606a98cae87c5fc80a3fa)
- Pre-Release v9.4.48.dev1 [`23e7005`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/23e700509793a49344e9b2ac02aecf5158a5c8a2)
- Pre-Release v9.4.48.dev2 [`99e28af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/99e28af8ae8ea4f7395dd5f5f6653fd9d21bb4ec)
- Pre-Release v9.4.48.dev3 [`6fb14eb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6fb14eb0a98377c5a82c97ab7cf98155bf70e7d4)
- Release v9.4.48 [`5663214`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/56632140c6c822a4925a3424c0c653396edf34dd)
- Cleaned up mass edit view code. [`e0fd191`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0fd19148b599a2ec6c2a2a6114d4d7fd6fa8ef7)
- Pre-Release v9.4.48.dev5 [`7322bff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7322bffb735a3545a8a2197788ef3cbbd76ffce6)
- Pre-Release v9.4.48.dev6 [`7c81274`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7c812742555cf4ac7a5a67787f92229137b8d878)
- Pre-Release v9.4.48.dev4 [`dfcf530`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dfcf530c414eb3af7ec787bfccc4bdc602fce7a5)
- Pre-Release v9.4.48.dev8 [`97cf604`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/97cf6049956ebe3536b32c5c3f65a0c98f00ceda)
- Pre-Release v9.4.48.dev7 [`4e68fe8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4e68fe80a4aecbb9effdedab3c8d53824154f1f9)
- Updated requirements [`c3de274`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c3de274e23772ea508905f78da6396d337b535a7)
- Updated message regarding installation of requirements if needed. [`bb861f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bb861f9a71c0758b0ba98c6875597efd2d38a485)
- Reverted tornado back to v4.5.2 [`977b8be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/977b8be2492d50f78f18d0e9915743aa78e3a497)
- Merge tag '9.4.47' into develop [`a2e4b43`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a2e4b43602ccebbb648ad01278370cc4c60805ba)
#### [9.4.47](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.46...9.4.47)
> 29 November 2018
- Release v9.4.47 [`b266867`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b2668675d45d0a30d203eeff9ad469e9797aa1bf)
- Merge tag '9.4.46' into develop [`f8c4e2d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f8c4e2d4869478dd25daf59a827ce796039cad06)
#### [9.4.46](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.45...9.4.46)
> 28 November 2018
- Release v9.4.46 [`80b928a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/80b928a4563a4e25b15ef1971c4f98b6954fa9bc)
- Merge tag '9.4.45' into develop [`4d4981d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d4981d2d7f9f4a36aedb5d71559888d58d2067c)
#### [9.4.45](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.44...9.4.45)
> 26 November 2018
- Release v9.4.45 [`e444d97`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e444d97edb7048df22a3eb02a86fc4d2a398f10b)
- Fixed Windows unicode issue with tzlocal. [`20da5e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/20da5e13daa5256d3c266b92ccdd6f9956d2258e)
- Merge tag '9.4.44' into develop [`d7695d3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d7695d3b24b2517c68ae97b74b012ab993349663)
#### [9.4.44](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.43...9.4.44)
> 25 November 2018
- Release v9.4.44 [`d07ac9d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d07ac9d0c5e7f9d1633c145c4a0cd253005dd5bf)
- Fixed issues with searching by scene numbers. [`29011fc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/29011fcc9aa0c670f5b18788f66634b981201c12)
- Merge tag '9.4.43' into develop [`7db2b7b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7db2b7b24c7c2ff9246fe284a9104020bbb90059)
#### [9.4.43](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.41...9.4.43)
> 25 November 2018
- Release v9.4.43 [`5882a99`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5882a9994378cb0e1c7cbeac4ed905f807d8da0b)
- Fixed episode search string fallback. [`db39bd2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/db39bd2f4a2d59e55cba2c7731b82bce84a0b96f)
- Merge tag '9.4.41' into develop [`adcf7e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/adcf7e114b2c1ea9141f1b23fc5719fa490e5d9f)
#### [9.4.41](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.40...9.4.41)
> 20 November 2018
- Fixed residual issue causing shows not to update from changes made to network timezone updater in previous update. [`461d0cc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/461d0cc741b2fc149339cd16c5e6f7c5af320e86)
- Release v9.4.41 [`dff28fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dff28fe492f33f9b8f811d8badfe3ec508c9435c)
- Pre-Release v9.4.41.dev1 [`0d519ff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0d519ffe7417a3feb6dc730a3d305c5e05ee71ba)
- Fixed show refreshes to work when show is paused if end-user edits, manually rescans, or mass updates. [`c578ff0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c578ff0ee3ca9ab6fa501dfd7d67dc3c15699ed7)
- Merge tag '9.4.40' into develop [`8a0fd2b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a0fd2b6ebc57903e091fb11bb9048b26bdf5d29)
#### [9.4.40](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.39...9.4.40)
> 18 November 2018
- Release v9.4.40 [`735245c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/735245c297546015e6be837ce63f94e2606dfe8c)
- Refactored network timezone functions. [`b538435`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b5384358eed524dfe61487cf826bab21ec0c5e2d)
- Refactored app to use pip2 instead of pip. [`b005c24`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b005c24a31296852096678475c7d56fde6f5272f)
- Refactored pypi publish to use twine [`8d1c1a6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8d1c1a609fef0e35ef112ece58944bc98fbcd8db)
- Fixed issue with database integrity checks. [`79d9ea1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/79d9ea150c48f3c5015bdafc3328ed18409eac20)
- Merge tag '9.4.39' into develop [`555d0dd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/555d0dd295fa73832c3284758a2e7b23bb6f5e40)
#### [9.4.39](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.38...9.4.39)
> 18 November 2018
- Release v9.4.39 [`d49c03b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d49c03beedb35d77a4cad1b9ef385c41e32d4913)
- Refactored grunt python commands to use virtual environment. [`4d3e19d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d3e19ddf976033fbbf8a540cc6bf6e11a44e2fe)
- Fixed freebsd init script, runs as sickrage user [`eff3ee9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eff3ee9c35da746ed47ab3585f876d15b3e057ef)
- Merge tag '9.4.38' into develop [`92e9f20`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/92e9f20b57613d2f8ec5b73a078ab218422bb20d)
#### [9.4.38](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.37...9.4.38)
> 17 November 2018
- Release v9.4.38 [`0aa52f3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0aa52f301d22ea3c7a4624c885d270dc7aa4ec1f)
- Merge tag '9.4.37' into develop [`65ebf15`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/65ebf15a0a0032d48ad4fa97a73844380a771b6a)
#### [9.4.37](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.36...9.4.37)
> 17 November 2018
- Release v9.4.37 [`ee79b9e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ee79b9e5e764d4ae204f79604772d88140d69515)
- Merge tag '9.4.36' into develop [`c2cc7d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c2cc7d76b58869ea789a9e8a030f6915ae9fddb6)
#### [9.4.36](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.35...9.4.36)
> 17 November 2018
- Pre-Release v9.4.36.dev3 [`5acf339`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5acf339c4127ab67dd153ca1899a8f8b97a37b85)
- Pre-Release v9.4.36.dev1 [`3f51fb3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3f51fb3a572063c04ba756ed6e7b3a6a947aafcb)
- Release v9.4.36 [`3c599a2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c599a27c883ed3f035946a5134bd456de46cfcf)
- Pre-Release v9.4.36.dev2 [`3299a1e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3299a1eb2a677b9df0618517c31d61e98291641d)
- Refactored DanishBits torrent provider. [`9048cd4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9048cd427b7eb3dce28bd0e11cace434624eff67)
- Merge tag '9.4.35' into develop [`202e359`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/202e35990d0b1dbaf1eaa69da85e8fceef2fa862)
#### [9.4.35](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.34...9.4.35)
> 16 November 2018
- Release v9.4.35 [`c92467e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c92467ed375e3af6f4dc1ab3ab3d215062cd4c38)
- Fixed Mako error related to no imdb_info present. [`11ac4c6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/11ac4c6c7d2e9c17495ab0218a67fc59ec2c0eff)
- Merge tag '9.4.34' into develop [`4688a3a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4688a3adddad1abacb7ffa33f5fdcfe6eed03594)
#### [9.4.34](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.32...9.4.34)
> 14 November 2018
- Release v9.4.33 [`4478e39`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4478e395ed88be67dd006cd6fe59a7075352a90b)
- Refactored new version string to web socket message. [`aaf7acf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aaf7acf967c9b7aa8604fb9e8f36f19b5b2a652d)
- Release v9.4.34 [`70d42c2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/70d42c244019b79947c5d28958c1c49861af912b)
- Merge tag '9.4.32' into develop [`116f31d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/116f31deded64a0c460f0d7052bd8f4ab027adea)
#### [9.4.32](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.31...9.4.32)
> 12 November 2018
- Release v9.4.32 [`d831f6f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d831f6f6bee01ef54070353ee59122c9406bdaae)
- Refactored speed.cd torrent provider to use cookie login. [`f298b17`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f298b171d9d69a3c5a0b801795efd18a3f46a7dd)
- Merge tag '9.4.31' into develop [`c84cb03`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c84cb03354ea6bc0038636460a980a8c6f946b03)
#### [9.4.31](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.30...9.4.31)
> 12 November 2018
- Pre-Release v9.4.31.dev4 [`4d0d839`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d0d839fcd143a96de38e88f88d5a3828348b0ba)
- Pre-Release v9.4.31.dev1 [`bbac0e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bbac0e2957bd9d4c317dd098a11fa253dbcc7462)
- Release v9.4.31 [`2abdafe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2abdafec3aa252ce0de276ff2c4cac96e31b3dca)
- Refactored show object class, cleaned up naming conventions for functions. [`34aa88c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/34aa88cd3ffddee185eaaa0fa008ed651dbeea81)
- Refactored queue current item property to always represent current running task. [`753625d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/753625dbef0962090721deb63d77f362518c6a9e)
- Pre-Release v9.4.31.dev3 [`12f8ad6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/12f8ad6f656b3a55ea2d020d0029af4eb439e534)
- Pre-Release v9.4.31.dev2 [`82115fc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/82115fc14e80baab2c4832c9db3b3c44d632e811)
- Pre-Release v9.4.31.dev5 [`971fc67`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/971fc67378c9baf21c51499080736f5e26a17fb0)
- Updater now waits for show queue to finish before updating. [`ae00748`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ae00748db9feb25234f381c08b8588eada2c1cd6)
- Merge tag '9.4.30' into develop [`d599f2b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d599f2b74cbd628c9fe50a630ced69ec0ab1a89e)
#### [9.4.30](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.29...9.4.30)
> 11 November 2018
- Pre-Release v9.4.30.dev1 [`90fdbb1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90fdbb120479786ffe9eb0654bb3201a24fed339)
- Refactored get, all, and get_many database functions. [`007df0a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/007df0a3da2b50466603d0eee51b96f5cb9159b0)
- Release v9.4.30 [`8bd128e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8bd128eb2b4696ec9adce3ae44b7bd9a4707a703)
- Merge tag '9.4.29' into develop [`e0edcfe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0edcfe80f3e21c7fc74d9a58c19b7f5f99adfcc)
#### [9.4.29](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.28...9.4.29)
> 11 November 2018
- Pre-Release v9.4.29.dev1 [`5eef56e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5eef56eaea05eb66fe70e7ae5222cf41de7217f1)
- Pre-Release v9.4.29.dev2 [`7d0812a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7d0812a7ee85ce229bbb054c475c70bd0ed7eaf4)
- Refactored naming convention of misc helper functions. [`eca1d42`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eca1d42f5af8e50bb7476fef0b23fe5a54b675bc)
- Cleaned up subtitles code. [`63f98ef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/63f98ef01d6e6ec7ec13a87d8515e37a61b89b2d)
- Release v9.4.29 [`f87d6ad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f87d6add4ea8ade3a08f35d8eb429a51a733206c)
- Fixed issue with displaying language flags in views [`1558dce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1558dceaeeb9812b937071dd8128c1bcaa32ce5c)
- Default subtitle language of English choosen if no language is specified in subtitle settings [`8028ae9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8028ae9787f27398b279ee548c405a7eaffb3f25)
- Merge tag '9.4.28' into develop [`02bdffe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/02bdffec8bf87c72b6911f61376069b8433569da)
#### [9.4.28](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.27...9.4.28)
> 10 November 2018
- Release v9.4.28 [`0173a0f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0173a0f21eba802621552a799b7ee170c4dbf03c)
- Merge tag '9.4.27' into develop [`d0c7b83`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d0c7b837109ea1b294f322a82788a07e045352dc)
#### [9.4.27](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.26...9.4.27)
> 10 November 2018
- Release v9.4.27 [`c5ea143`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c5ea143edc7b8519afe2ffd8d63a755e102cbf96)
- Refactored misc errors to warnings. [`4127ed3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4127ed3ad22d784f116c9885096433ef3b9f0f05)
- Fixed issue for missing database indexes. [`7c31b0c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7c31b0c7715cde8881fee90265fdb32d51970923)
- Refactored misc errors to warnings. [`3f20cdd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3f20cdd00a238a98703bf813c201282e1967be2b)
- Merge tag '9.4.26' into develop [`83909dd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/83909dd6b414299ee68fb89194560a0f973783a3)
#### [9.4.26](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.25...9.4.26)
> 10 November 2018
- Removed restoring of application ID from backup/restore functions [`0972ec5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0972ec5000a20818a5e0aba57b962cbb060eb8aa)
- Fixed issue with file browser and clicking on files not properly choosing file and closing browser dialog. [`9e4dc5f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e4dc5ff61163b33bb0f8bf3683def9b2cee84b3)
- Release v9.4.26 [`78c64b1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/78c64b17ff2deebd3c35696fc0ee6255d2f976e2)
- Merge tag '9.4.25' into develop [`2cfa68a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2cfa68aede1fb7b92bd9e78b4174fdae6ad14091)
#### [9.4.25](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.24...9.4.25)
> 10 November 2018
- Refactored misc logging errors to warnings. [`af3348b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/af3348bae91f0621eb442bcaae1e0d390025cce1)
- Release v9.4.25 [`9cf70c3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9cf70c3f7aa2800f33f852a663525d9a6264a188)
- Merge tag '9.4.24' into develop [`bdde3e5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bdde3e54d31c2b46c64a6df5a351923af7964d82)
#### [9.4.24](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.23...9.4.24)
> 9 November 2018
- Release v9.4.24 [`73acd71`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/73acd711e3e05f0c125990741d412f4600428f0c)
- Merge tag '9.4.23' into develop [`fd0de4a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fd0de4a6397a3ec6020794151eab26bacb1de1bd)
#### [9.4.23](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.22...9.4.23)
> 9 November 2018
- Release v9.4.23 [`e9ca9af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e9ca9af36b48629393807c2c90cf86156ce163e8)
- Merge tag '9.4.22' into develop [`d023922`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d023922e259a257a908d4fcb93c4761e011faac0)
#### [9.4.22](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.21...9.4.22)
> 8 November 2018
- Fixed startup issues with systemd init script. [`d705db2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d705db2a044ecacfa7021453bce2f09cc4771385)
- Release v9.4.22 [`f98b5e8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f98b5e824299aaad42ae376002f8b9b2bb2e9e56)
- Merge tag '9.4.21' into develop [`3f9541f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3f9541f194d98a8c100a6ed377c8a2217b7047d4)
#### [9.4.21](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.20...9.4.21)
> 8 November 2018
- Release v9.4.21 [`5bb165d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5bb165de7e5d82eef90baede54754465774cce05)
- Merge tag '9.4.20' into develop [`b9f9540`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9f9540e9f67bd9a1a5357ef12cc2315f3e05d79)
#### [9.4.20](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.19...9.4.20)
> 7 November 2018
- Removed backlog cycle time [`dfa2238`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dfa2238d55530ffce0184168b14e04e5d0ca9579)
- Release v9.4.20 [`6b3ab52`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6b3ab522c6c7fd74750336a5b6ea181957c0751c)
- Merge tag '9.4.19' into develop [`21d71b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/21d71b210bf709c94f99597169d56a3ed35fa328)
#### [9.4.19](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.18...9.4.19)
> 6 November 2018
- Fixed issues with saving provider settings. [`d394cb1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d394cb1cd789fd8e51ec10a37129c85403bb51ab)
- Release v9.4.19 [`e7526ee`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e7526eeb70c42443b53e78916b9f7dd0e1ddaf4e)
- Merge tag '9.4.18' into develop [`572f53c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/572f53c535739d148a7a6b718d631cf72fa0dfe6)
#### [9.4.18](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.17...9.4.18)
> 6 November 2018
- Release v9.4.18 [`6d5e91c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6d5e91c8686149aaf5733fd6bb17fb1abb70fe8e)
- Merge tag '9.4.17' into develop [`8d5d216`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8d5d216af27c20ef5c3bf059fae9a8f4aebde182)
#### [9.4.17](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.16...9.4.17)
> 6 November 2018
- Release v9.4.17 [`3bbf2ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3bbf2caa4c32999cfa2d4d07093600abd5aec438)
- Merge tag '9.4.16' into develop [`b156ea3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b156ea3ab293283d1e3533d9833816737a488138)
#### [9.4.16](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.15...9.4.16)
> 6 November 2018
- Fixed issue with Media Browser metadata nfo creation [`086e274`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/086e2749b57b839ad900e356d67ceb9f8a277e21)
- Release v9.4.16 [`8963ac9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8963ac9cb6b2a5f6246d431f49efb522c12409bd)
- "Unable to find episode with date" warnings now only shown for shows in library. [`8869731`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8869731c44a5341af04f91ea5433f07e5fa8fd8b)
- Fixed active column for home show display [`6441354`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/64413549af1935df06f012fe69df4b49a55ff069)
- Merge tag '9.4.15' into develop [`e8e6151`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e8e6151772bd9f696d22e2ac9f214264d02fef12)
#### [9.4.15](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.14...9.4.15)
> 4 November 2018
- Fixed attribute error caused by none type when shutting down web server. [`9ca8af6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9ca8af6baee61c6ef9118df6c483e9c99cbe122a)
- Release v9.4.15 [`180d59d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/180d59dd36e8d074166b4cafb7159dd45af33792)
- Merge tag '9.4.14' into develop [`e8b39fd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e8b39fd9fdf23f879169a992d9ece2faedd10baa)
#### [9.4.14](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.13...9.4.14)
> 4 November 2018
- Release v9.4.14 [`7596f3b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7596f3b91e72e51082614d02855711f1d5376ef5)
- Merge tag '9.4.13' into develop [`c580156`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c580156313886207dc0691e8178b8e093a81cddd)
#### [9.4.13](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.12...9.4.13)
> 3 November 2018
- Release v9.4.13 [`c506406`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c506406c03832405a88472f4d10309f240aeaf6f)
- Merge tag '9.4.12' into develop [`c59b9e9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c59b9e9216dae2bd8efb9efbb4fe0d718cf99840)
#### [9.4.12](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.11...9.4.12)
> 3 November 2018
- Release v9.4.12 [`73b760b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/73b760bf018bee6c8ee2218594a01a9eb4564394)
- Merge tag '9.4.11' into develop [`9e677d3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e677d3c09fd59403e850c5f785cc952740e47fb)
#### [9.4.11](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.10...9.4.11)
> 3 November 2018
- Fixed issues with properly identifying multi-part episodes. [`e8e2d80`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e8e2d805fedda3e72c21f0f82f516a20c7a3b985)
- Release v9.4.11 [`f6754e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f6754e444ae048fbf7c30fcb21d9ee2609969ca9)
- Merge tag '9.4.10' into develop [`bd02659`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bd0265980edb97b73405bb188e919061860e0d1d)
#### [9.4.10](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.9...9.4.10)
> 3 November 2018
- Release v9.4.10 [`429568d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/429568d3239beac99d0764abf0c2d244624759fe)
- Merge tag '9.4.9' into develop [`36bd6a6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/36bd6a669aaf50659cfef9c32c8067ae2a314692)
#### [9.4.9](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.8...9.4.9)
> 3 November 2018
- Moved building of name cache for app start to io loop callback, [`e073791`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0737918ebe11186b25e852d455d4a7df66722cd)
- Release v9.4.9 [`39c0a09`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/39c0a0985ae7ff7600f1f3f0c046c47d28822fc8)
- Merge tag '9.4.8' into develop [`f7f2f89`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f7f2f8953c7aa2f3e53dc5f2cf000925842e872d)
#### [9.4.8](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.7...9.4.8)
> 3 November 2018
- Fixed typo [`231a032`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/231a032bc9b2aa3b26e4259e3b424330f063be15)
- Release v9.4.8 [`c35d07b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c35d07b4be041fe88114ac9cb6ec54014b29c2cd)
- Merge tag '9.4.7' into develop [`14f03a8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/14f03a8fa0b0863f97e7681bad3581d91caf5bce)
#### [9.4.7](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.6...9.4.7)
> 3 November 2018
- Refactored cloudflare bypass. [`63eed66`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/63eed6657c6c3a47aa989ff9eaba21d9fa98c248)
- Release v9.4.7 [`697d36a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/697d36a14f9913f2b4d74e4e8a6a210f992c0d90)
- Merge tag '9.4.6' into develop [`613dae0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/613dae03745a2e16672f1fe0f930d8fb7c1d0ab7)
#### [9.4.6](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.5...9.4.6)
> 3 November 2018
- Release v9.4.6 [`ad3bf92`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ad3bf928a89ae4db5d6fecdc561dab7ed1bec009)
- Refactored speed.cd provider code. [`9678e16`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9678e166b021382c395109f4157953d336439c93)
- Fixed issue with email notifications and saving addresses. [`68b1f56`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/68b1f564c8bef3cc0f56c4e4fcd2595a54d6fcc1)
- Merge tag '9.4.5' into develop [`a125bed`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a125bed116279a8b65fc07e68f82cf7b6f321938)
#### [9.4.5](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.4...9.4.5)
> 3 November 2018
- Release v9.4.5 [`bcccf74`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bcccf7419752b4f591556d0f7fe31dcadac85e3e)
- Merge tag '9.4.4' into develop [`f00e4ac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f00e4ace6af50d983f6c7b26f101fbc0cc290ded)
#### [9.4.4](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.3...9.4.4)
> 28 October 2018
- Release v9.4.4 [`f91c70b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f91c70b0c667ad9141af355ee85e1fac24e3c218)
- Merge tag '9.4.3' into develop [`14251ef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/14251ef55f2b4c25293d32c131d459bb0db33b13)
#### [9.4.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.2...9.4.3)
> 28 October 2018
- Release v9.4.3 [`d32be97`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d32be976f90f1add837d03e201a24c847a12784a)
- Fixed issue with unrar unpack directory setting [`f7c0464`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f7c04648e0708a1755d3e1afe7957a646c78bad5)
- Merge tag '9.4.2' into develop [`15c00e7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15c00e7205fe5de6e8ff1720fe28cce2cff1007a)
#### [9.4.2](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.4.1...9.4.2)
> 28 October 2018
- Release v9.4.2 [`206857b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/206857b39bea7958a779b6d3cfc8cca1c1c7432a)
- Disabled warning for when no nzb/torrent provider is picked if no nzb/torrent client enabled. [`7e3baa8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7e3baa8fc05eb3dcdae3a8d422ed9121a65ea8cd)
- Clears name cache with indexerid and show name [`1ad42fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1ad42febe7f57c17e2f548bbda4acb1ab1a84c4c)
- Merge tag '9.4.1' into develop [`89fd3bc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/89fd3bc50c18ea6b7b1728592e7dc09009e272b7)
#### [9.4.1](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.99...9.4.1)
> 27 October 2018
- Release v9.3.100 [`3dbd257`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3dbd25703277c6fbc73b7b1e1ae6a0096fb39f09)
- Release v9.4.1 [`bf93454`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bf93454fd4bfd6463a9c0001ff1d8deffff94cf3)
- Removed app_id and replaced with app_sub. [`479d80e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/479d80ec2f35a155d519dc2d3f6506ec6a06abc2)
- Merge tag '9.3.99' into develop [`0ebb11a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0ebb11a36147ef72a930f865a08f12e5b41522cb)
#### [9.3.99](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.98...9.3.99)
> 21 October 2018
- Release v9.3.99 [`33ea2f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/33ea2f1c98c084371bbb7021eb25cffe7fc6e710)
- Merge tag '9.3.98' into develop [`147e412`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/147e412b640e34f1bde856fda4db6f4a6bc94ae0)
#### [9.3.98](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.97...9.3.98)
> 21 October 2018
- Release v9.3.98 [`e3b3be9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e3b3be9f191f4fafd21c385789d361dc1f489e07)
- Fixed issues with matching shows with parsed results when containing accents [`d5ec001`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d5ec0014afafe9aa97b03350497d99c1a39eae1b)
- Merge tag '9.3.97' into develop [`d4214c5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d4214c534c36e9dbfa8c16500fd66fec68aeae46)
#### [9.3.97](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.96...9.3.97)
> 21 October 2018
- Release v9.3.97 [`84de9fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/84de9fe24e88bfcffebd1ac33482e18b9839800c)
- Fixed issues with network timezones [`a5f7b6a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a5f7b6ac95fe8f2c0a2916acea6ff7f8e86ce6b5)
- Merge tag '9.3.96' into develop [`6ab4906`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6ab4906d9ce29604eb0cf5c021381965d8149146)
#### [9.3.96](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.95...9.3.96)
> 17 October 2018
- Release v9.3.96 [`ed1b33e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ed1b33ed9052af24a391604c39e237a191c1dccd)
- Fixed setting caps issue when searching newznab providers [`ecb1600`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ecb1600225377ba04aaa9699d8b6eeb0320d23ad)
- Fixed 'Notification' object has no attribute 'type' issue. [`bbbc6cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bbbc6cbe75d14eba7b890550f39ace75a611746c)
- Merge tag '9.3.95' into develop [`9730121`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9730121d44a0525910f591fecfc29531158db5e0)
#### [9.3.95](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.94...9.3.95)
> 16 October 2018
- Release v9.3.95 [`aad016d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aad016deedf92ea4ae29675a62d2253307d12107)
- Fixed issue with checking for stash in output of git cmds [`0f07f4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0f07f4b092f65527572cfb56dbaddb7b9e6fe777)
- Merge tag '9.3.94' into develop [`b69a6ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b69a6ceb3ce76dd2ce26fdffd860a5d4b67a31a0)
#### [9.3.94](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.93...9.3.94)
> 15 October 2018
- Release v9.3.94 [`8b3319d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8b3319df798a16e62187d9d8af96c7b28faa4584)
- Update .gitlab-ci.yml [`bc472cc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bc472ccf5a6d46f9734f1150ea47bed831bc3082)
- Update .gitlab-ci.yml [`47ce84c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/47ce84c3748cde76dffc352bf804f5fa40142ed6)
- Merge tag '9.3.93' into develop [`bdf23cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bdf23cb9e2641ddfc98045dd2876ca3ff14169c0)
#### [9.3.93](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.92...9.3.93)
> 15 October 2018
- Release v9.3.93 [`eb1a642`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eb1a642f843c8a63238ec69351f628f17c44a4b6)
- Merge tag '9.3.92' into develop [`91b372f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/91b372f692238efceb469ab50100eb8d344f0b5c)
#### [9.3.92](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.91...9.3.92)
> 15 October 2018
- Release v9.3.92 [`13ff53a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/13ff53a20dcb256d8afdb03fe45797e55b6f2330)
- Updated .gitlab-ci.yml [`def0213`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/def0213d5ecd81075da20aee2947973a3f247ce2)
- Merge tag '9.3.91' into develop [`ba167b1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ba167b1fcf1eadc45ba498f053f4d8e2ce80b5ab)
#### [9.3.91](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.90...9.3.91)
> 15 October 2018
- Release v9.3.91 [`4500af0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4500af0d8c996bd2dfd34c6884daab86a4924d1d)
- Updated .gitlab-ci.yml [`b226cf4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b226cf406524f7b076038cec467fa6522abffdd7)
- Merge tag '9.3.90' into develop [`a36dfab`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a36dfabdb96ec4ecdd77ef3fe57f5866cdc0edd0)
#### [9.3.90](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.89...9.3.90)
> 15 October 2018
- Release v9.3.90 [`b4d3c18`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b4d3c180e53331cd7eb5451ae861f8ee63191f84)
- Updated Dockerfile. [`01f719f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/01f719f66acd031d18a024d00a8f9fca933ce2ca)
- Updated .gitignore [`70b40c6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/70b40c6e89664e9d5e7d4bfef7d12415b945b991)
- Merge tag '9.3.89' into develop [`5fe3b52`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5fe3b5205920085d7c361fb8e49e8ef591a81926)
#### [9.3.89](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.88...9.3.89)
> 15 October 2018
- Release v9.3.89 [`89b5a00`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/89b5a0033806d558742fe715be6ba13d373aed9c)
- Merge tag '9.3.88' into develop [`184a4c5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/184a4c53b0510c576ec9a904e530450144cb6c94)
#### [9.3.88](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.87...9.3.88)
> 14 October 2018
- Release v9.3.88 [`b01ca47`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b01ca4726d3968c397544e6581b085ef35cf7cac)
- Fixed issue with custom provider not being saved when using spaces for names. [`79735d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/79735d78234be196897b9d89b1d2a2968af8f4f5)
- Fixed issue#286 - added support for non-english indexer images [`e2132a2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e2132a29f4a352d9968b2e0edb36de7873e62bab)
- Fixed issue with custom providers having spaces in their names that was causing settings to not save [`6d8c60a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6d8c60a0be25c688dac4c68becb5d4d9c3fb3fb0)
- Fixed issues with removing custom torrent/newznab providers [`23f9684`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/23f9684ea44d40b25e0bafbc97d97aef192c432c)
- Merge tag '9.3.87' into develop [`ef827f7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ef827f755358f23bdcbb7ee25c251673ec1f9ab0)
#### [9.3.87](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.86...9.3.87)
> 14 October 2018
- Release v9.3.87 [`d186f55`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d186f557ff504abf5c43163ca5b98793eef5e6ec)
- Fixed issue with freebsd init script not daemonizing the app [`ca05ceb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ca05cebac405049854ff28d372815f62ff240858)
- Merge tag '9.3.86' into develop [`f17fcbb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f17fcbb57fbe9d247f20c2ad63910bab6cabca22)
#### [9.3.86](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.85...9.3.86)
> 14 October 2018
- Release v9.3.86 [`10fc6b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/10fc6b3ff0b4e7d9591c666a1f4ddc8bc3290d82)
- Merge tag '9.3.85' into develop [`2736e83`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2736e8393cff5de3ae4c458d946e3bc2ca4dcefd)
#### [9.3.85](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.84...9.3.85)
> 13 October 2018
- Release v9.3.85 [`b0c7dc9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0c7dc9a20ef1b7b61832e67067223f3ddd93335)
- Fixed issue with saving subtitle language settings [`2e0a378`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2e0a378077fba575c27980a9a07906bbcb81d2a4)
- Merge tag '9.3.84' into develop [`8a79fa6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a79fa698750fa1695b7a8e44929703a92c3cb65)
#### [9.3.84](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.83...9.3.84)
> 13 October 2018
- Release v9.3.84 [`57a541f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/57a541fed7e96cbef3406aa7c81e8f6b9530616d)
- Merge tag '9.3.83' into develop [`56e078d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/56e078dc67da782559ebfc435082c4412d6dbb73)
#### [9.3.83](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.82...9.3.83)
> 13 October 2018
- Release v9.3.83 [`7891d45`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7891d45004ec3773379c27602cabcf8a5e220a38)
- Pre-Release v9.3.83.dev1 [`256f26b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/256f26b6220fb4659cd08beb95106f3ca4b173ef)
- Merge tag '9.3.82' into develop [`fad12a4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fad12a41ec821cfe817533a0be98c84e9ec30786)
#### [9.3.82](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.81...9.3.82)
> 13 October 2018
- Release v9.3.82 [`536c3ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/536c3bafcc6e22397008633f0b3dfe3e57b8a47f)
- Fixed issue with displaying provider icons for custom providers [`a216e2b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a216e2b06b5453dd3509ef2ce8595550b22ec8b9)
- Fixed issue with re-scanning existing show episodes that do not contain the show name in the filename [`a120b3e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a120b3e893df61f362804a8aef78cfe2d56c1c00)
- Merge tag '9.3.81' into develop [`b798eb6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b798eb6f5bc7da8ed743c869b1109ff5bdf09ee8)
#### [9.3.81](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.80...9.3.81)
> 12 October 2018
- Release v9.3.81 [`f29e97d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f29e97d24b19eb8c087c458d41dc20f6a4cf7b4f)
- Fixed issue with building Dockerfile. [`35fb7f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/35fb7f1e4cf42ce030d6971702cec24130c1e28a)
- Pre-Release v9.3.81.dev1 [`7141eec`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7141eeca8bf0985be8d4291a61129f6522ca7bd3)
- Merge tag '9.3.80' into develop [`37896dd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/37896dd2392bdc2737d1a8a90ff696355cf84511)
#### [9.3.80](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.79...9.3.80)
> 8 October 2018
- Pre-Release v9.3.80.dev5 [`f64a196`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f64a1968771fc7644272c29aa53612fe4fa41390)
- Pre-Release v9.3.80.dev3 [`be55b94`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/be55b94549dd1d2bd9386e0fbe065b11a313ff77)
- Pre-Release v9.3.80.dev2 [`6e16bcc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6e16bcca027dddf89bd5633ae1a9ee1b426174e1)
- Pre-Release v9.3.80.dev1 [`ec020ec`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ec020ece8c95746d5e966585394a244589e2d2d1)
- Release v9.3.80 [`a9e7913`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a9e791391a49aa91f821d5722ea890a9197b28c8)
- Pre-Release v9.3.80.dev6 [`615cf7d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/615cf7d959426718a5ddaf7ba8251290c703c9b3)
- Pre-Release v9.3.80.dev4 [`8a1fd06`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a1fd0616b650043512503d4111b31d9f7a9bce6)
- Fixed issue #273 - location not found when adding/removing a show [`7b0a85e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b0a85e3733dfc9569113501da8e4f8513bf08b4)
- Updated remaining ui-icon icons to fontawesome. [`bf4e106`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bf4e1063f87dc4da35eac7551ffb028e7da628fa)
- Fixed saving allowed video exts [`e3e893f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e3e893f09a3d0f6f2bc981ded7ff80c820e72cdc)
- Fixed issue with magnet links missing torrent trackers [`d2b5aab`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d2b5aab6e9defdce9be205d5fd0aed8f8210e19e)
- Merge tag '9.3.79' into develop [`ed4cc53`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ed4cc53d4859a6e5ba7f21e78dc33bf20a5d6249)
#### [9.3.79](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.78...9.3.79)
> 18 September 2018
- Release v9.3.79 [`5bf995b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5bf995bb97fbf884f9dfa37b19a435706aa6b899)
- Pre-Release v9.3.79.dev3 [`2868350`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/28683500d7cb793aba4a8754ede440b9dc13ca11)
- Pre-Release v9.3.79.dev2 [`15f9781`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15f97813bf9668fa219916518910667500f3760c)
- Pre-Release v9.3.79.dev10 [`a7d0209`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a7d020967a2270f453a4e5a6529d714b58f20410)
- Pre-Release v9.3.79.dev8 [`3419702`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3419702f782c6b759391e4997a576ea56c0cac03)
- Pre-Release v9.3.79.dev9 [`09b1857`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/09b1857d7c156036d686063c05d080f72b3c454d)
- Pre-Release v9.3.79.dev7 [`a4a4814`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4a4814be6c2329eeb061e34dfcfc805aa6f89d2)
- Pre-Release v9.3.79.dev1 [`e6fab35`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e6fab35257a8293b47ed28dea662b6222b47c51c)
- Pre-Release v9.3.79.dev6 [`605f75c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/605f75c12c716ef9be66de777e2abb7fe28cf246)
- Pre-Release v9.3.79.dev5 [`bd67a69`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bd67a69eb4f8ced22a8a28248cb22684b53a12d4)
- Pre-Release v9.3.79.dev4 [`31a9c17`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/31a9c1719b4f7d51f309b9cd273e063ee71c88c9)
- Refactored Zooqle torrent provider to handling paging results [`f39ab1c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f39ab1c2c36465dba8d6e4d3117af4e7e9df4e4a)
- Fixed issue when displaying multiple modals same page, 2nd modal wasn't removing scrollbar. [`e8445dd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e8445dd06f8c1ffa1b446867861e59366b50dea5)
- Fixed issue with custom webroot and too many redirects [`dbb7543`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dbb754376bf9c6ea775bc829852194f17eb33aad)
- Hardcoded Zooqle torrent provider to search for english torrents [`69668c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/69668c720b0c8ec1175a301621f9553763aa2a68)
- Fixed search issue with Zooqle torrent provider. [`f87f0b0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f87f0b0a8e1c60510f3c4bf827b12a15af90ca59)
- Merge tag '9.3.78' into develop [`a22d25c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a22d25cffc14bef7d44cde5a456e0e4042dfaa1b)
#### [9.3.78](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.77...9.3.78)
> 14 September 2018
- Release v9.3.78 [`90f31c5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90f31c5e916cf4755f1ed84a31d3bf6b41e61f11)
- Merge tag '9.3.77' into develop [`77bbb38`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/77bbb38fa78ad9f34d3adb83505eded380aea41d)
#### [9.3.77](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.76...9.3.77)
> 13 September 2018
- Release v9.3.77 [`d6195df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d6195dfab470cc44706bbde9cbc7d9e9d12159b8)
- Merge tag '9.3.76' into develop [`58aabf0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/58aabf0c22f6fab661fc464d722229be5dad083d)
#### [9.3.76](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.75...9.3.76)
> 9 September 2018
- Release v9.3.76 [`23d3379`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/23d3379e78cdd86102e4a3b3fddcbfaf19dd36b9)
- Merge tag '9.3.75' into develop [`fd577ef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fd577ef0e0e2f070e26ff60d5cc4568c045c8d13)
#### [9.3.75](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.74...9.3.75)
> 9 September 2018
- Release v9.3.75 [`80a1cf8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/80a1cf8db3cc7baa7f5df97434899d8c37c22b0d)
- Merge tag '9.3.74' into develop [`f16c8f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f16c8f14b2d17e46d4e84766303b961efee3d7e6)
#### [9.3.74](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.73...9.3.74)
> 9 September 2018
- Pre-Release v9.3.74.dev1 [`fd54d1e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fd54d1e939057f2e13a7627e0ab23da1bc1bb2ff)
- Release v9.3.74 [`0a5590f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a5590f810546e100ac94cb836983cb323f67429)
- Merge tag '9.3.73' into develop [`2120c47`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2120c477def535e21af001383d9da4b600736dfb)
#### [9.3.73](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.72...9.3.73)
> 8 September 2018
- Release v9.3.73 [`d4b634c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d4b634c47a3bb9b2362921fb75a03874c54c4e66)
- Merge tag '9.3.72' into develop [`be3c708`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/be3c7088ede0a9db31742e38b1f6ac1631be0fe3)
#### [9.3.72](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.71...9.3.72)
> 8 September 2018
- Pre-Release v9.3.72.dev1 [`5c3c795`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5c3c795e74f52a561641e4ae8b615c055b11683c)
- Release v9.3.72 [`0f56bf7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0f56bf7cd4a91b001a2f6457207145f7455459c0)
- Merge tag '9.3.71' into develop [`a658730`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a658730fd95953bb43a4fec5c0433206e939d051)
#### [9.3.71](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.70...9.3.71)
> 8 September 2018
- Release v9.3.71 [`3b8de1e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3b8de1e63623707333254a886b5a84325320a25a)
- Merge tag '9.3.70' into develop [`874b988`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/874b9884ceb51f1926e8da5aa3bebffc5f942a5c)
#### [9.3.70](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.69...9.3.70)
> 8 September 2018
- Pre-Release v9.3.70.dev2 [`d1aa98d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d1aa98d46d344f8e7ecfa69f5c99b8b328048b38)
- Pre-Release v9.3.70.dev1 [`1c0d920`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c0d9201e0be3a430e555da15ce185f7d0053377)
- Release v9.3.70 [`cf75694`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cf75694a08562c62c39dc5b3187afe3cc3530e74)
- Merge tag '9.3.69' into develop [`1b9fd1c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1b9fd1c827c84cd52aaa9b182ac0d68ad1b04798)
#### [9.3.69](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.68...9.3.69)
> 5 September 2018
- Release v9.3.69 [`e93f949`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e93f949d25fefdde8ea647cd3a8a5f345f70834e)
- Merge tag '9.3.68' into develop [`26e066b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/26e066bb7eaf2e86aa972f3a276d837948470e1e)
#### [9.3.68](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.67...9.3.68)
> 4 September 2018
- Release v9.3.68 [`51f6fb2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/51f6fb2d3f09e106c936f1995e1428d04a99bef4)
- Merge tag '9.3.67' into develop [`e3a9fb9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e3a9fb98660bd26611455103ec863ccc4c207ffa)
#### [9.3.67](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.66...9.3.67)
> 1 September 2018
- Release v9.3.67 [`c11dace`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c11daceaebf727ac512d0f237da2e8386c70dfa7)
- Fixed issue #255 - total episode count incorrect. [`1430717`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1430717a2e9c06a26ba2eee5db6b23337d833343)
- Merge tag '9.3.66' into develop [`f8a371e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f8a371e5286258ca277c6c43cbde6fae2ce13d93)
#### [9.3.66](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.65...9.3.66)
> 1 September 2018
- Release v9.3.66 [`569f95c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/569f95cf36a10efee2f43fa2728e0c13f04dad2e)
- Pre-Release v9.3.66.dev1 [`4ac6773`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4ac6773b2703eef9f7466987b7770254e8aea77b)
- Pre-Release v9.3.66.dev2 [`4c62c8c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4c62c8c361325f6fbba7a35e7413e7c3eb65d7f6)
- Disabled changelog from popping after a new update [`33b3f9c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/33b3f9cdbb4a5bc694a8bb144045eb6f0cd058c1)
- Fixed issue #265 - Unable to detect internal IP address in order to add UPnP portmap [`1ee6798`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1ee67982e3c4c1a248e482eed74cdcce511bf215)
- Merge tag '9.3.65' into develop [`1e9d65b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1e9d65bf6bf3c9c9672bc5845a4eecea9aa94c0f)
#### [9.3.65](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.64...9.3.65)
> 30 August 2018
- Pre-Release v9.3.65.dev1 [`a534896`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a53489648115a9bbaf51fa44e96a266d48d4add3)
- Pre-Release v9.3.65.dev2 [`61c0376`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/61c0376896c1cce4c38d18e3cd97d232fa0e42a6)
- Pre-Release v9.3.65.dev3 [`cd59c7f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cd59c7f270c1ab092f8a688eb13d6258fc29b456)
- Release v9.3.65 [`ab769b0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ab769b0e0ee46bfd9499874266864becb4e31d4d)
- Failed processing skips paused shows and archived episodes. [`9d880bd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9d880bd135506f4008b208af72627e83d04daab7)
- Fixed issues with failed snatch searcher attempting to re-download archived episodes [`889fa19`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/889fa19ff518bdf1e86cdab414148a4c6621bbf8)
- Merge tag '9.3.64' into develop [`f11067d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f11067d8927606aab66fa5f999966d3e155acb02)
#### [9.3.64](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.63...9.3.64)
> 29 August 2018
- Release v9.3.64 [`dc90396`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dc90396a10734b50e4f0d46b780a6db26d851408)
- Merge tag '9.3.63' into develop [`b763c62`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b763c62c3106b0a89580a31d2525078cd74cb8a4)
#### [9.3.63](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.62...9.3.63)
> 27 August 2018
- Release v9.3.63 [`0c2e95d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0c2e95dbb0b24f0c3fac001ee9fc5cf98654f4e5)
- Fixed javascript issue when adding existing shows [`9e66cf5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e66cf5e245e3ae1f1a08dfa5b38cb36611068b1)
- Merge tag '9.3.62' into develop [`b6f7597`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b6f759757eb9085831869b25234578892b976d1c)
#### [9.3.62](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.61...9.3.62)
> 27 August 2018
- Release v9.3.62 [`6b01822`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6b0182242e42e2ec31ecd43b24d04aca288de620)
- Merge tag '9.3.61' into develop [`36d258d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/36d258d4ea697dbf47bb160e06d7687bef60da8c)
#### [9.3.61](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.60...9.3.61)
> 27 August 2018
- Release v9.3.61 [`c4c732f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c4c732fa42ea37bc0bc82cfefbf1647cd5d71cd4)
- Merge tag '9.3.60' into develop [`c0274a9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c0274a9019d031ae52aa58ee54d79c0f5cec44b3)
#### [9.3.60](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.59...9.3.60)
> 26 August 2018
- Release v9.3.60 [`ebd6252`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ebd6252d2dade3c3931b5828a042a775bb5c6e0e)
- Pre-Release v9.3.60.dev1 [`1b42b83`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1b42b83bc30892253a55e510738a2664ddf71b01)
- Fixed quality badge for manual searches [`8279ece`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8279ecea96d594c017810795d90d813fbdba1ac4)
- Fixed unicode issues with timezone updater [`8b6981b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8b6981b478593465a16faa7d38362c8c13ae011f)
- Fixed issue where click event for adding root folders was being fired more then twice. [`55e4104`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/55e4104173d6df8b2be134b0bf8e8cb9fb5ce9b6)
- Fixed spacing for status view [`9797220`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/97972204b3b15f5b2aceaf991d9f8c64e24dfa6e)
- Merge tag '9.3.59' into develop [`7530eec`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7530eece814a208d5737d7618b03d708998b084d)
#### [9.3.59](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.58...9.3.59)
> 24 August 2018
- Pre-Release v9.3.59.dev1 [`5ddb5de`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ddb5de239de1e31986b4010eef274ef6933601f)
- Pre-Release v9.3.59.dev2 [`a1cc57d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a1cc57dcc11764d1c983e4c188e6a570f8575f42)
- Misc improvements made to websockets code [`30e4803`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/30e4803ccc3ec064691b0263f1ca6306141f27f0)
- Improvements made to tornado web handler code [`096b055`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/096b055df997d63670dfa3c845e3d0fd80e4f41b)
- Release v9.3.59 [`fb31d87`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fb31d8799d439f98b1682f590b6ecad337cad3a6)
- Pre-Release v9.3.59.dev3 [`2a1d2ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2a1d2ceb466e1e2155931acc2ab524f52b8e9ecc)
- Misc improvements made to websockets code [`b18bd58`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b18bd58357342e823913f7fc1434340ce7b4ff43)
- Merge tag '9.3.58' into develop [`c5e3128`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c5e3128287f8fad0528d6a4a9560f8862a63f1db)
#### [9.3.58](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.57...9.3.58)
> 23 August 2018
- Release v9.3.58 [`a7f3541`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a7f3541d68ff702581a809fb3a6e12d92e847e9e)
- Pre-Release v9.3.58.dev1 [`2f40c76`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f40c76d01bb7c81f042bb7cd0e2c192744a158d)
- Pre-Release v9.3.58.dev2 [`bd35aae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bd35aae62a625f68ced0d5ba8fdd12efa40b315e)
- Fixed issue #253 - Provider Option Missing Cookie Field [`5f0e3bf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5f0e3bf8c20140374c45e9cf5930041ad9e9b91b)
- Fixed issues with custom web roots and redirects [`faefa9d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/faefa9d122f6987d7caad8ba21391d83745a8d81)
- Merge tag '9.3.57' into develop [`e25112d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e25112dafad5231b42389277089737772582c522)
#### [9.3.57](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.56...9.3.57)
> 19 August 2018
- Release v9.3.57 [`e5b5706`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e5b570692527782465406d7253b400a59f1c3ad6)
- Merge tag '9.3.56' into develop [`a7128ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a7128ce75605ee6c847984b6923d97de2724af32)
#### [9.3.56](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.55...9.3.56)
> 19 August 2018
- Pre-Release v9.3.56.dev1 [`900b680`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/900b680a94948ddf8c144ea497b197770af46a52)
- Pre-Release v9.3.56.dev13 [`c6f1503`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c6f150349a7c0e6a8329963ddef3036a0841b43d)
- Pre-Release v9.3.56.dev27 [`10de224`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/10de2248a6d6dcecdf776d9323084789d95ffce8)
- Migrating away from Bower to NPM/WebPack [`d73439e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d73439ecfc8f010c369bde03ffdc7fc79a370165)
- Pre-Release v9.3.56.dev10 [`8c90243`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8c90243e9fe40cb9519662fab42f1733f38b15de)
- Pre-Release v9.3.56.dev18 [`d6b5a4a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d6b5a4a06ecb13aaa0501bc168ecd69ef4ebcee5)
- Pre-Release v9.3.56.dev12 [`07e1703`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/07e1703efdf86f1eb97a3149368b7aa28cda61bf)
- Migrating away from Bower to NPM/WebPack [`a4b58c9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4b58c9a05e7496a0ba9bc21683608fa662723b6)
- Pre-Release v9.3.56.dev14 [`b40951e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b40951e9ce2de7ae4b9a7a984032dcda50a9324e)
- Changed table text color to dark for display show view [`443ec81`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/443ec81baa6398f307b802f64c7fe45c80b09318)
- Pre-Release v9.3.56.dev17 [`d569f06`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d569f06fb00e746a59862794ea2ee6f2e25449c9)
- Pre-Release v9.3.56.dev5 [`e39068a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e39068a610caefc862c178ca1645caa3d794f146)
- Pre-Release v9.3.56.dev9 [`f33330a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f33330af7cfd665b311f5486a1f12c1f9edcedf3)
- Migrated tablesorter theme to bootstrap 4.x for home view [`9f14867`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9f14867bbd204547222a55c67a9154cc84eb94a8)
- Pre-Release v9.3.56.dev4 [`24b4751`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/24b47510b5fe007ddb4167200f835b98c82fd30b)
- Pre-Release v9.3.56.dev8 [`e588aa6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e588aa6bcf02582eea96291d7c2a62620d2749af)
- Pre-Release v9.3.56.dev3 [`45d2074`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/45d20742591c605e6ed3ac2a83a8f3cc3731abf4)
- Pre-Release v9.3.56.dev11 [`3acc96b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3acc96bba90d8e06b859cb9eeb578641d34b96a2)
- Pre-Release v9.3.56.dev7 [`876ddfc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/876ddfcad0729e88a8f858ae05767859f70c3952)
- Pre-Release v9.3.56.dev24 [`26635da`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/26635daa55d5cae649a0f2f8d3377c26d87604bd)
- Refactored table class spacing/padding and column widths [`19cb817`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/19cb817eb85d0e3117d17c1935a7f7163301d075)
- Pre-Release v9.3.56.dev19 [`e69a0e5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e69a0e5d4789e07bae0d1903f950041b2b5b8daf)
- Pre-Release v9.3.56.dev6 [`5a27b14`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5a27b146673ba5659e45c01b3624ccbc9d2c06af)
- Fixed broken toggle buttons [`8efa7cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8efa7cbffecb21330813e568584228887f2cef08)
- Refactored config views to Bootstrap 4.x [`b912b2e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b912b2ec53a842ac171a2d2dd257cda0f984f4ec)
- Fixed issues with modals not displaying correctly [`93bd3ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/93bd3ce1495b0210f3518bc909aca31b3dd543aa)
- Pre-Release v9.3.56.dev2 [`5ac6bac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ac6bacb4ad89e420bc2be99bc4cd82f14cf6f63)
- Fixed issue with saving provider settings [`332017d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/332017d2dbd1f34353bfbcbfa455ed8601a0018f)
- Pre-Release v9.3.56.dev16 [`096927a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/096927ade8d3f6b15ae77fd89e207ed828c8699d)
- Fixed status text styling issues for episode rows in display show view [`479026c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/479026cf6c6a0a395738adef7364d493791860a5)
- Removed bootbox jquery package [`e12e04f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e12e04f1986575925a6603d5653fd218c5168bc3)
- Fixed IMDb star ratings for display show view [`96a1978`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/96a197855ad5b6316237479112d3fa32dd2eb580)
- Removed focus box shadow for quick search form control [`b96888a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b96888a09940d5e1a877c19c5cf6a9e98c39e69b)
- Fixed file browser modal [`1243962`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/12439625cbfc0725751d29226f435424074fd925)
- Refactored responsive column for views [`fbc0c9e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fbc0c9e559749a6c8144a27c22290d4f9a3223c6)
- Refactored schedule view [`453ca1a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/453ca1a9ce96bfc2e028819996455f28d2ef55ae)
- Refactored display show view to Bootstrap 4.x [`a4fa4da`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4fa4da5752d7a72d2188bb25792b0b488ea2cbb)
- Pre-Release v9.3.56.dev29 [`e26fd2e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e26fd2ee8f0c7394b68aa9d42be2e660115efa87)
- Pre-Release v9.3.56.dev25 [`c9367a6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c9367a673cf0dfd20b9b7835c8e07fb3326ea597)
- Created themed scss classes [`6cd3963`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6cd3963fbf8eba31732bcbeb8998348c959f5aa6)
- Refactored notifications config view [`085af56`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/085af5605885ecbdec2181da13c524264109dcfc)
- Refactored episode naming view and misc config views [`8b4add8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8b4add8014e9ed7ed0458e0bb855748a570d48a1)
- Migrated file browser modal to bootstrap 4 [`bce28bd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bce28bdfd25cb7443850f0b64190d3079e46b86c)
- Refactored edit show view responsiveness [`2466e65`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2466e651ec48ed6e2d67d5a91d0537d3decd82bd)
- Refactored all config views [`ef5ceee`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ef5ceee60989a6d2220947a7828e15a9e910d2e2)
- Converted all glyphicons icons to fontawesome icons [`0672255`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/067225529f48d1693ba3b3d36b86d03ace6123f9)
- Refactored add new show view to bootstrap 4 [`a3ff9ab`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a3ff9ababd29a8774b68d817d7f2e70f9e40d2fc)
- Misc code corrections and cleanups [`97b4239`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/97b423963a3f7e8c6a6d8af201bb983d96cf0d27)
- Refactored history view [`0fdb6df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0fdb6df7d861b587d02abe74ca4848281cf8833a)
- Migrated status view to bootstrap 4 [`bc2a0f2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bc2a0f212079516f628e02240dd67527d4ca54ba)
- Refactored mass update view [`1df34fa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1df34fab96e9edf68d65dbf5f304ace7407a38cf)
- Fixed responsiveness for add shows template [`e8d562b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e8d562b830b752e6d2663505ddfd44511f92cd67)
- Misc style changes [`0beb0e7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0beb0e799c9badc7627068b52749c1b786f01133)
- Fixed main shows page show details footer [`03c08d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/03c08d7038da8e37f1c055753ab3f21414765a3a)
- Pre-Release v9.3.56.dev28 [`a2aa340`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a2aa3404e6382d13c91b0e0cd6b252882aea4431)
- Upgraded tablesorter to use bootstrap 4.x [`fc2ec2b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fc2ec2ba4997c9f02d391f6d719dec579563a14e)
- Migrated provider and subtitle image references to sprite references [`b3107c2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b3107c267821831fe7a0c085ef47201921c809c6)
- Updated grunt tasks [`6afa4c2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6afa4c2cc91cbb96fb93657288d952e4df9301ce)
- Converted provider icons to sprites [`f94568a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f94568a0c163f6da1b925ceb5318327b0f99f0fb)
- Refactored edit show view to Bootstrap 4.x [`fd227d5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fd227d51aa9196d16bbee479a25b2c13d64322de)
- Migrated add existing shows view to bootstrap 4 [`e1ea56c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e1ea56c41682fb9d28c29f07578241736319f642)
- Migrated add trakt show view to bootstrap 4 [`7abe9f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7abe9f9b7e39cacc0b2e4f607febadfea825843b)
- Misc code cleanup [`71b4cfa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/71b4cfac26c0ed9c73460ae80041a1243dcb14b7)
- Migrated home view network logo's from images to sprites [`961b90c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/961b90cbd137d80194ed4691994b1cc449a6cabb)
- Migrated imdb popular shows view to bootstrap 4 [`2fa2261`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2fa2261c4a361e7dcde8aa15abe0fcdccec4ef65)
- Refactored mass update view and manage queues view [`dfb4f99`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dfb4f992376ddc562543ca83f860283a4d574b28)
- Refactored metadata config view [`22d3071`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22d30716fa5c72d6490c2a42815290f9e328ace4)
- Misc style changes [`524cb0a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/524cb0a8646c1bcf8a98c31c5184f426185d6d2c)
- Pre-Release v9.3.56.dev21 [`b8c4de7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8c4de70c544de7ff3cf0a790f7c81deccdbc605)
- Refactored missing subtitles view [`427b651`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/427b651a8b06520452115f5bab5e692f12c43d11)
- Merged overall_stats and show_stat functions [`08cb03c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08cb03c443c4346592e7647f2e1ec7e4347eff49)
- Migrated config providers view to bootstrap 4 [`d2cea58`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d2cea5803a25523e1824bff265620acc2ab40b57)
- Misc code cleanup [`69cee25`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/69cee2531d167d309a1222bb3caad0d11b21739e)
- Release v9.3.56 [`b1dc06d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b1dc06dd712af50d50c1df9ca181e29324450028)
- Misc updates to tests [`b9bbb26`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9bbb261c1592787dec2adff133608acfdd199ca)
- Refactored failed history view [`6727208`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6727208ca2efca90f10dcf6afc5102a65eb03a5a)
- Pre-Release v9.3.56.dev26 [`c60cbb3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c60cbb3162b041bc7da1dfead6dab7acfe46a074)
- Pre-Release v9.3.56.dev23 [`3ae007d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3ae007d538a75893712539d98d0672b26df5e58f)
- Pre-Release v9.3.56.dev22 [`908bb53`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/908bb53f6fc654ea90a5b32dec9e7a45ed4409d4)
- Pre-Release v9.3.56.dev20 [`fdeaf28`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fdeaf28c7ea28601f390ceb00aa724bffbe78b41)
- Pre-Release v9.3.56.dev15 [`486eb8c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/486eb8cbe9853a9881e71593d5589167cf54b1df)
- Migrated more icons to font awesome [`fe6e1f0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fe6e1f04a2bfc1e79f172cccc2336bd99fec1ecb)
- Migrated loading, queued, searching icons to font awesome icons [`1e21e2d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1e21e2d241fa8b704555d7bc3b8f55127caa3222)
- Fixed progressbar backgrounds and misc margin tweaks [`8aefe4c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8aefe4cc583e9772976ebdc5b85e2ba819fcb16a)
- Fixed table text wraps [`b0e6922`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0e692288ab85ad77c1ee9ce9af69be28c11d578)
- Misc changes to package tests. [`46f21f5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/46f21f5bc0c19519578eca36226cad655ea97b23)
- Fixed logs view [`efff7db`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/efff7dbcd166f1edd3a9363f858298e71f3bb6cf)
- Migrated upnp client from threaded object to scheduler job, resolves shutdown/restart problems [`d590b01`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d590b016e8982b950f55fb28a7c8775affc5a294)
- individual shows view now gathers total show size from episode file sizes in database [`ea140ab`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ea140ab2ee63c5e4f11885aa681da354571ade33)
- Refactored content column size for large devices, small to medium devices are now full-width [`76afe3b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/76afe3b42bbfca13a33fe28271af132045433730)
- Fixed issue with network logo being off-center [`ebcd017`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ebcd017397426b153f39fd1a66e1bec653eb0389)
- Refactored restart view page [`d5f8615`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d5f8615494a4afe409f2ffe7ffcb47bf6e3a38a9)
- Updated notifications view [`df9b9e3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/df9b9e3ef509fd816d4ac0b4df0884ab1e3b4a85)
- Fixed issues with displaying show network logo's [`6004bc4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6004bc4f5aa2f317ff32b467346f20e5ca671e7e)
- Converted provider icons to sprites [`f626619`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f6266197c8bab0fb3e7340e708c63e78fdb60a5c)
- Fixed issues with multi-episode search results with more then 6 episodes in result. [`9cba816`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9cba8168297963d1862815575072590c1a68f018)
- Refactored manual post-processing view responsiveness [`2742737`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2742737d9788251b752efb992e53843c64a5c5fc)
- Refactored display show view [`b24cc27`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b24cc27343531390e135a9a6ed6d6b5178ac14ef)
- Removed select column control from shows view [`3a87793`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3a8779317a9ddfc98bdc77c4510986be1ce95abb)
- Fixed gaierror's for ssdp [`e27a959`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e27a9595f2846cddf51fd708825151613cfbc5b3)
- Misc code migrates to bootstrap 4 [`476f90a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/476f90ac336e4ae4ade0f60a6e6b1f29a18eda2e)
- Re-enabled closing of databases on shutdown/restart [`af4abb6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/af4abb699721354e60b28bcde1ce9eeffab83c15)
- Fixed provider view list items [`1867aaf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1867aaffbaa23eb4389621a8140dedc8c63fc039)
- Removed code that was preventing show refreshes from happening due to show updates being in queue. [`481f291`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/481f2910b85bbbf9054185e414694032d80b3749)
- Disabled closing database on shutdown/restart of app [`e6f1422`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e6f14220633089e7201ef27180750f03eeb97c8a)
- Fixed redirect issue when trying to login to a app thats already linked to another account [`9b5ed21`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9b5ed215b3d6b3a660fbd6e1e267abbf59287ef7)
- Refactored table show show/episode column for history view [`d086087`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d0860872dc9022ffbcdb7f26dcd4b0a892cbf2f9)
- Refactored list group in subtitles config view [`169b960`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/169b960801fedcf35daeb12084d0009c17d7b3eb)
- Fixed genre row alignment for display show view [`9c41f4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9c41f4b3c445771861a4832e77185d454bfd3e5f)
- Fixed missing icons in navbar [`c702306`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c702306d0cef31e4825d7ecf920029d173518313)
- Updated gitignore file [`901a870`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/901a870520509c8a42f6537a977f406617eb914e)
- Made quicksearch content easier to read [`d56b876`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d56b876d25cf3e3a2adc68f0b53f8ad0b4b80dbf)
- Removed unrequired top margin spacing [`1a7bca1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1a7bca1e8434a188a05f123f38848a7a24e28feb)
- Fixed case-insensitive sorting for small poster view [`f52c99b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f52c99be489c98f1646e34690d2327b889f07dd9)
- Refactored layouts for main shows view [`e61f206`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e61f20638d5519e3125b28f148238ae1471de9a5)
- Fixed issue where MultiPartEpisode was being appended to all episodes and not just multi-part episodes. [`1cfa2f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1cfa2f95f362216b185095d8c91578fd388626a4)
- Fix for issue #244 - reverse proxy [`764a9f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/764a9f16c59980b561f75a293e844454b3f723de)
- Fixed newline issue with error view [`51b6726`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/51b6726d2956b89c3888c12ecf55d39f6aed93af)
- Reverted text-nowrap class for schedule view table episode name column [`7020ea5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7020ea5e44ceb2faace014c98c240aa5d3b94d25)
- Fixed issue with retrieving image thumbnails from Fanart.tv [`1f9d56a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f9d56ac8685c2088caf6844a2035fb3a4b7b394)
- Misc code cleanup [`d115e61`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d115e6163fb514c7a6445ce880ed255f9216139e)
- Updated gitignore file [`6f84b0d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6f84b0d10f202213bc2ce957670eac7e0088932a)
- Re-sized buttons bar for main view [`736d021`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/736d021ed99d9645a229a2f6e33b0d98352a7cd4)
- Merge tag '9.3.55' into develop [`ff10465`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ff10465acf3fd910f433f1e6a1f98876e2ead724)
#### [9.3.55](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.54...9.3.55)
> 13 July 2018
- Release v9.3.55 [`fd36e3d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fd36e3df4b72bf8bc2d11c0dc4a3ee068e1927df)
- Updated gruntfile [`a60f7af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a60f7af44a6cc44f16a470eb526140ed79f521c0)
- Updated Yggtorrent provider base url [`2f5ba4a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f5ba4a35d50d71ec2b68028110c6c9dc91609a6)
- Merge tag '9.3.54' into develop [`8c50c1c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8c50c1cb7f1f6237f51d73fa05fe87ee9e306c42)
#### [9.3.54](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.53...9.3.54)
> 8 July 2018
- Release v9.3.54 [`ae015ef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ae015eff31db5344dec4e710d5c9ae49aabe372a)
- Pre-Release v9.3.54.dev1 [`2923c07`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2923c07cae8a7acf1e8b78f6a92a3d84a075b051)
- Fixed getEpisode function to handle absolute episode numbers of zero [`e666331`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e6663313f550ce268e928be38af3182e4f40f061)
- Merge tag '9.3.53' into develop [`1ba84b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1ba84b2b6284b748e55237572193dd4daa002d10)
#### [9.3.53](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.52...9.3.53)
> 7 July 2018
- Release v9.3.53 [`dc3cc1c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dc3cc1c8ad568f239cd1a378f5be8c6bb9923e47)
- Merge tag '9.3.52' into develop [`ece0c59`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ece0c5975e658bf09beacf8cab7af630df79c908)
#### [9.3.52](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.51...9.3.52)
> 6 July 2018
- Release v9.3.52 [`f3b315e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f3b315eeb96237f8e59926a25b6f5efb0b0880e3)
- Merge tag '9.3.51' into develop [`8084037`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8084037ddfe31fd56b5d196d94b0e2480f09291f)
#### [9.3.51](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.50...9.3.51)
> 6 July 2018
- Release v9.3.51 [`9d335cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9d335cb7b4a8c7bcfad54a99309d9b91ecb6d4f3)
- Merge tag '9.3.50' into develop [`d9b2a40`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d9b2a4064a2f79681aa2f404f78f34bb9831c3df)
#### [9.3.50](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.49...9.3.50)
> 4 July 2018
- Release v9.3.50 [`591578b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/591578b8181ab597d5d44f1c2333c3ee88e4d711)
- Merge tag '9.3.49' into develop [`38b2e05`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/38b2e0550e47ae9eee568da0ead55c9bb02a6205)
#### [9.3.49](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.48...9.3.49)
> 29 June 2018
- Release v9.3.49 [`867b799`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/867b79907e086696384a3ab1668a91ae3b4c5824)
- Merge tag '9.3.48' into develop [`86b57e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/86b57e4a158e06d32ded32becc2040b62cdd6b53)
#### [9.3.48](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.47...9.3.48)
> 28 June 2018
- Release v9.3.48 [`3d27b4e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3d27b4e42ab25b2c6fdaebf0cb3b92cfdc63d8e2)
- Minor updates to login handler [`b3ca706`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b3ca7065047a62ebc369c1f8f3c831537d230d9e)
- Merge tag '9.3.47' into develop [`5136f53`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5136f53d66195d6047898ea6f0a75aafefc490cc)
#### [9.3.47](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.46...9.3.47)
> 25 June 2018
- Release v9.3.47 [`ecf829f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ecf829f521f4858d03fc172f2cf7f043103c6e17)
- Merge tag '9.3.46' into develop [`28e7255`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/28e7255fcf4afa5294850335c70f1da6db45f0ac)
#### [9.3.46](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.45...9.3.46)
> 25 June 2018
- Release v9.3.46 [`40ffc7a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/40ffc7a9b3544feca04f0e161178306959507db3)
- Merge tag '9.3.45' into develop [`c1e8863`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c1e8863a01a5ad0db8289cca15478cf6bf8ad2a9)
#### [9.3.45](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.44...9.3.45)
> 24 June 2018
- Release v9.3.45 [`05e41d5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/05e41d58a916e0533b47dbbd808cf28599a3a8ea)
- Fixed issue with UPnP getting incorrect internal IP address [`dcaff48`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dcaff48e85047acfe26a74ed4abfb9fa9589e92a)
- Merge tag '9.3.44' into develop [`84c951b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/84c951bdbf5183beb95d7131721eb9ada020cfab)
#### [9.3.44](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.43...9.3.44)
> 24 June 2018
- Release v9.3.44 [`38bd1fc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/38bd1fcfa5d021a9ce0c7350de8029128c13511f)
- Merge tag '9.3.43' into develop [`6a716e6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6a716e69f8e5dda9a3bd1e42aa0b2c0d92451bc8)
#### [9.3.43](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.42...9.3.43)
> 22 June 2018
- Release v9.3.43 [`21d03f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/21d03f967d9d08fa150b43bfcb2cd396e45c0477)
- Merge tag '9.3.42' into develop [`f48f9d6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f48f9d6b9aa92a6f7b44907b4a3e5d36333485bb)
#### [9.3.42](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.41...9.3.42)
> 22 June 2018
- Release v9.3.42 [`42893d0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/42893d01393ce103a2953a36df827a5c3ff14052)
- Merge tag '9.3.41' into develop [`92d0968`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/92d0968c38111e4e173ddd624ca0213e9cb146a5)
#### [9.3.41](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.40...9.3.41)
> 21 June 2018
- Release v9.3.41 [`abf1b98`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/abf1b98e6e8651c32232884645211c5663d75676)
- Merge tag '9.3.40' into develop [`4de2ca5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4de2ca50280bd54ddad6607420dc0911444a5b22)
#### [9.3.40](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.39...9.3.40)
> 21 June 2018
- Release v9.3.40 [`8bd7022`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8bd7022e937f3ef428454e9a344be5704130a318)
- Merge tag '9.3.39' into develop [`3604c27`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3604c274a8b808d21d4370f5d29b5aa1a447f7bf)
#### [9.3.39](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.38...9.3.39)
> 21 June 2018
- Release v9.3.39 [`36ce10b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/36ce10b33b298ca2c6a64010ef6cb73d1b697136)
- Merge tag '9.3.38' into develop [`56451a3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/56451a314dd7898fd0ecd04add4f7dd7d66d8e87)
#### [9.3.38](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.37...9.3.38)
> 21 June 2018
- Release v9.3.38 [`c2a903e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c2a903eea1833a941e07f01fba7b612fc3453fa7)
- Fixed issue with how data is formatted on return for app api [`4ee3db6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4ee3db6abd667085971f8a4a4c19f81b2e74e250)
- Merge tag '9.3.37' into develop [`074994d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/074994d64d019bf3a959d95e0a1aec6e08f467d1)
#### [9.3.37](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.36...9.3.37)
> 20 June 2018
- Release v9.3.37 [`08580c9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08580c93e4b6044011cb45fc8a4e31302ba33568)
- Merge tag '9.3.36' into develop [`05918e7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/05918e7d52b5b378e74da3624a4d5fce36fc95b2)
#### [9.3.36](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.35...9.3.36)
> 20 June 2018
- Pre-Release v9.3.36.dev1 [`e6f02d4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e6f02d43e0c503e2aa0467586e387010b3c08d82)
- Release v9.3.36 [`5e91170`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e91170ee506ef0e20365103185efb7b531f6de9)
- Merge tag '9.3.35' into develop [`39b4fd7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/39b4fd74c1709e85ff85bc157b2cea8bf0e48232)
#### [9.3.35](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.34...9.3.35)
> 16 June 2018
- Pre-Release v9.3.35.dev1 [`bcdcce3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bcdcce3b46dbfbcc6bbd4c0656f7bce8131d420d)
- Release v9.3.35 [`c800afc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c800afc496f6a5cb1da455d61e19e8345523cabf)
- Pre-Release v9.3.35.dev2 [`8ee962a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8ee962a2148a8694f1f149c2a3a53b334af5fbd7)
- Changed placement of announcement's for main layout [`f316113`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f316113c5dcdf44ee459350ac6dea6b70db32a93)
- Fixed requirements issues [`2eef0d8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2eef0d80ca90196964f86c5a494b112333bad48f)
- Merge tag '9.3.34' into develop [`0a9a43a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a9a43af3064b993f654289d554f8c7664ad7f29)
#### [9.3.34](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.29...9.3.34)
> 10 June 2018
- Release v9.3.34 [`7bd322b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7bd322b57e86b9139d8458db0d00601dd737b7c4)
- Merge tag '9.3.29' into develop [`10d35c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/10d35c418e9d72cbf1f3c3c6c267a8046b801141)
#### [9.3.29](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.28...9.3.29)
> 4 June 2018
- Release v9.3.29 [`a65bc0f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a65bc0f10881de71fea5e2d72261209b47172216)
- Merge tag '9.3.28' into develop [`df57762`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/df57762923edbe048eb5e635c14df62660cf2ad9)
#### [9.3.28](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.27...9.3.28)
> 1 June 2018
- Release v9.3.28 [`1277227`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1277227ca2b9c2ddbdf7c7908a1fc8606db78493)
- Merge tag '9.3.27' into develop [`528077b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/528077b2a6c53b50fc3ee909e6028b9758f3a388)
#### [9.3.27](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.26...9.3.27)
> 1 June 2018
- Pre-Release v9.3.27.dev1 [`22b37e3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22b37e36d3a93606a3055f24999eb35d9fe0983e)
- Release v9.3.27 [`924a877`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/924a877bfbb0603adf16ee83b003ff514b279229)
- Migrated from oauth2 client credential grant to password grant [`4dd25e6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4dd25e6125773c1d385e47d32e70c4fdfd62a89f)
- Removes existing symlink or hardlink file if exists when creating new links [`1ad45d2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1ad45d2473107d2f525215bb3251b87ae0c7e9ee)
- Misc changes/fixes for database calls [`510fe7d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/510fe7d224def156a0b274290255767b123f31eb)
- Fixed issue #224 - backlog searches not working [`7f39cc3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f39cc3322dabfd739460d7acf95101d74640b15)
- Merge tag '9.3.26' into develop [`0103654`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0103654b00051ee11dafcf0a1e74baffbbdfb59d)
#### [9.3.26](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.25...9.3.26)
> 24 May 2018
- Release v9.3.26 [`d861c0c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d861c0cd554e51ba80f881eb50d6572017da2777)
- Fixed issue with parsing failed quality for episodes [`eee20d0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eee20d009c78a03c63448cc6ec9cd76e9124d6bf)
- Merge tag '9.3.25' into develop [`e7a623d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e7a623dbe8a5220088945fdf62a678be6adb9ea4)
#### [9.3.25](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.24...9.3.25)
> 21 May 2018
- Release v9.3.25 [`06d160f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/06d160f88df0612ba9d26dc58972b72afc4c1969)
- Fixed issue with unexpected keyword agrument 'skip_downloaded' [`f7f75e7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f7f75e7e07e915047a786d7508520cef1948118d)
- Merge tag '9.3.24' into develop [`f20942e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f20942eae5b365b83612664615e4e6566a9be58b)
#### [9.3.24](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.23...9.3.24)
> 20 May 2018
- Release v9.3.24 [`706c89e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/706c89eb74b4681c829219a75f78dde4f63b2946)
- Merge tag '9.3.23' into develop [`bcdaf05`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bcdaf056dea568ad41897e048f46180242214d53)
#### [9.3.23](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.22...9.3.23)
> 19 May 2018
- Pre-Release v9.3.23.dev2 [`8a40c41`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a40c418e985161825a6be803bf4bbe831582d4c)
- Pre-Release v9.3.23.dev1 [`c6fd81b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c6fd81b4814c5288a1eaf22f1fc640349febc462)
- Converted log error to warning for Discord client [`0f68f72`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0f68f72cf3fe3c40b273957891158b329cc7d4e3)
- Converted archive_firstmatch to skip_downloaded option, skips upgrading quality of downloaded episodes [`249b6b0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/249b6b0b56bb7165b8d5d16703ca4891916cb413)
- Release v9.3.23 [`7bd2298`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7bd22986c1403a51e8579c89de920991b5d84c23)
- Misc typo corrections [`5f5592c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5f5592c0a2d0ec33802a99028b491375ff6c3830)
- Misc small fixes [`a3c7441`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a3c7441c613cd03d325bbf16b02d9a78214b83d4)
- Fixed issues with downloading subtitles [`15c6a47`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15c6a4781b2b65c1cbcccbf8b02eee0c83bbae07)
- Converted for loop to while loop for database upgrade function [`1ff0bc5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1ff0bc5fad58be966cb57fb16d77f1cd191a6120)
- Merge tag '9.3.22' into develop [`bc707df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bc707df928139b1b9a7abaeaa0354a6b582a0587)
#### [9.3.22](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.21...9.3.22)
> 17 May 2018
- Pre-Release v9.3.22.dev2 [`d2f59fc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d2f59fc841591ffe4045af45cd6288d2a00b6037)
- Pre-Release v9.3.22.dev3 [`6ea67b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6ea67b352856f4f8f9afb01b37d4459655c26e61)
- Pre-Release v9.3.22.dev1 [`2476478`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/24764780c26e084c53f1f352422e28f0dd824e31)
- Pre-Release v9.3.22.dev4 [`8acce0d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8acce0d122be778e105c39632f5ad544f2854ad1)
- Release v9.3.22 [`1630902`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/16309028881a327e73138c76630ed54c48e044de)
- Merge tag '9.3.21' into develop [`5256f22`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5256f22ed95acb832f96399ff35788b906a7c7f7)
#### [9.3.21](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.20...9.3.21)
> 13 May 2018
- New Crowdin translations [`#10`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/10)
- Pre-Release v9.3.21.dev3 [`7be1210`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7be1210d2e486d02b477bc45b0190ffbb0a17916)
- Pre-Release v9.3.21.dev2 [`5c626f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5c626f6f62c03153f2ccf7298ccee82d5ffc137c)
- Pre-Release v9.3.21.dev4 [`52d12af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/52d12afba09a2402402aa958a91042eb8c563387)
- Release v9.3.21 [`0869c48`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0869c486aaf2144f7c8df8efd494aa7aa3e1110e)
- Changed log levels from error to warning for misc [`fcdf2e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fcdf2e49c79d28ddda82adc6252cdc1bb47b415a)
- Pre-Release v9.3.21.dev1 [`8b1ac6e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8b1ac6e6fcc815a3aefd7f2201a78b5c7f9bb6fc)
- Fixed bug in backlog searcher that was incorrectly comparing date ordinals causing zero results to be found [`ea98ece`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ea98ecef7163059cd3fa3cee80c8dcebb9c86914)
- Updated Grunt tasks [`5bb7da0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5bb7da01b04b8fa1bb38f8b229a2452acabde4cc)
- Changed iptorrents login url [`d1b612a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d1b612ae89e4fa54d6d947ecc671b774c2407f99)
- Update Crowdin configuration file [`392eda4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/392eda46a334270a16d5e1c23b27d46630b5b0a2)
- Merge tag '9.3.20' into develop [`51a525f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/51a525f9c6e0dfa023116a7d72dfaabd165c4846)
#### [9.3.20](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.19...9.3.20)
> 6 May 2018
- Release v9.3.20 [`7c77db3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7c77db3d79dc2eefa6222556b8c501a95ba9b313)
- Merged failed database into main database [`8ba19bd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8ba19bdc87235321ccfc181bcaaea374051399bc)
- Fixed UnicodeEncode errors when saving subtitles [`67d8ac1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/67d8ac1a77fde26fc1c47b24bf68c92d88729138)
- Refactoring search client code [`b7cc531`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b7cc53185ff96b8d1cac6b3eb40ccf2e23c87788)
- Pre-Release v9.3.20.dev2 [`b5b3a06`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b5b3a065c1241acc33616a2cce49e3cf7e13f5d6)
- Pre-Release v9.3.20.dev5 [`b89ab1b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b89ab1b124a78bba7c08d06f175a00ddc48e3340)
- Fixed redirect on login [`e0d01bd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0d01bdd25cc765c6e24966efa2bae50fe84590b)
- Pre-Release v9.3.20.dev6 [`b9fa094`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9fa094bf3fc1cd4eedb5c6b6fb5c41277de6842)
- Pre-Release v9.3.20.dev4 [`0e6ce30`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0e6ce30622f8cc102a0e08d6db108746ea198d4c)
- Pre-Release v9.3.20.dev3 [`f69a02b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f69a02bad00e2d23c92f85596e53685ece83bbdf)
- Pre-Release v9.3.20.dev1 [`ae451c1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ae451c1cc002df20829dd97c1f854f476f944e5b)
- Merge tag '9.3.19' into develop [`031cb4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/031cb4ba760325c45da006671cb58436484880e6)
#### [9.3.19](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.18...9.3.19)
> 5 May 2018
- Release v9.3.19 [`50769a1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/50769a1bbc6057e239a42baa42cb69262169f248)
- Pre-Release v9.3.19.dev3 [`c478436`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c4784362c64a086b3a880b4179047793a6d13688)
- Pre-Release v9.3.19.dev2 [`ee3e0d4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ee3e0d4da2a2687d1608d9ff4ecda5c3262e3406)
- Pre-Release v9.3.19.dev1 [`793d2a5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/793d2a51e6ae1c24348c5ca7547988e4683630ea)
- Merge tag '9.3.18' into develop [`e599a2a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e599a2a3fbf55fc0cf889b018cd29d8ab808b874)
#### [9.3.18](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.17...9.3.18)
> 4 May 2018
- Release v9.3.18 [`885708b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/885708bba81cb98f99aa7d290e6d788e02378c3e)
- Refactoring of provider code [`821cc99`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/821cc99e46e52e04947e64ccf6ed0ed1e5beaf23)
- View Changelog now reads changelog.md file [`de8804b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/de8804b1c55c63d6db15e5187d539947a13f611b)
- Changed log levels from error to warning where needed [`1759db6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1759db68ef9faa462f243a8a5d855a59d2452008)
- Converted errors to warnings for DelugeD client [`a81ccaf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a81ccafa833d68dfdc8c4df187a4faea6a1ca2ac)
- Pre-Release v9.3.18.dev3 [`4a12c79`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4a12c79426c8cde8f3d283b5f04c6b6eac7c53bc)
- Pre-Release v9.3.18.dev2 [`2a46cba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2a46cbafc2f3f8270fca583bba4b28f186b2dba8)
- Pre-Release v9.3.18.dev1 [`f85ba73`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f85ba730e2ace8e63ffcca5dd2732a146c8a4b57)
- Merge tag '9.3.17' into develop [`9cd46df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9cd46df61936922fc5e690f74146f74c16387439)
#### [9.3.17](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.16...9.3.17)
> 1 May 2018
- Release v9.3.17 [`bd058f0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bd058f0914fc5e24b51ae2f690b95f15bd3eb358)
- Changed logging level from error to warning when trying to load episodes from directory and the show or episode is not found [`3781227`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/37812271ac54b8246bd3b33b61566e0ea529efd9)
- Merge tag '9.3.16' into develop [`0781b99`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0781b99651dac7b7265cf64a2e3835fa400f2d33)
#### [9.3.16](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.15...9.3.16)
> 30 April 2018
- Release v9.3.16 [`1a7b0ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1a7b0cad3e6fae45dcd75054efcffcb55aadb66f)
- Merge tag '9.3.15' into develop [`11dae1c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/11dae1c45e5c2ed814acb1b8bcda65d115d6631c)
#### [9.3.15](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.14...9.3.15)
> 30 April 2018
- Release v9.3.15 [`49c633f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/49c633f317df7a0530bd397fbfa4ed4a9a053d8f)
- Prevent sentry log handler from having logging level changed [`48105f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/48105f62076bd257b8eebeb71a05897924d05e49)
- Merge tag '9.3.14' into develop [`8df79c6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8df79c64d6a2974bce83536bcaf04078849b6de8)
#### [9.3.14](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.13...9.3.14)
> 30 April 2018
- Release v9.3.14 [`1c5d2fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c5d2fe33aceb8eb7788cd6469a117b98cf7aa43)
- Merge tag '9.3.13' into develop [`02ff5dc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/02ff5dc0b7b5be8b01ebbb5b75cc84489384960b)
#### [9.3.13](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.12...9.3.13)
> 30 April 2018
- Release v9.3.13 [`ab62087`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ab620872fddd499298b8a2625bcd74a1ec9a1b3a)
- Fixed issue with sending email notifications [`244264a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/244264aa51ea76bafb11d1d08d7849eea8572a4c)
- Pre-Release v9.3.13.dev1 [`e0bc4ae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0bc4ae3396423137fb86a432389a44ab458a166)
- Pre-Release v9.3.13.dev4 [`55b2e91`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/55b2e911c04957dfd08145018d33bc15d1c7b120)
- Pre-Release v9.3.13.dev5 [`f3546f0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f3546f0525d708fbb63054876a9e6b446ea046ac)
- Pre-Release v9.3.13.dev2 [`35791f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/35791f42a3d768cceaac2a3868f3657360490124)
- Merge tag '9.3.12' into develop [`212c0c6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/212c0c62b227f9ae248c4ad1e7a3a1ca0571da1e)
#### [9.3.12](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.11...9.3.12)
> 29 April 2018
- Release v9.3.12 [`3a13aca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3a13acaffb09e0979baac260ee10454670b729a5)
- Updated sentry api url [`03e1ced`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/03e1cedd38876c78f78c9e2d344fc00c9da863c7)
- Merge tag '9.3.11' into develop [`7419ff4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7419ff4c444b2674a4687dc6eec6bc234e30b9d0)
#### [9.3.11](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.10...9.3.11)
> 29 April 2018
- Release v9.3.11 [`de5e70f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/de5e70f8b0a7237825c0b38493562a2215a97198)
- Fixed log level of sentry logging handler to log errors only [`ae29eb5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ae29eb58b1d40a230ed68236ec2f348363065590)
- Pre-Release v9.3.11.dev1 [`bebb5f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bebb5f668d8c70ba89d552cdfd74881413486bf8)
- Merge tag '9.3.10' into develop [`58d0f20`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/58d0f20cc4ad27f2f272124d370230b22bcb202b)
#### [9.3.10](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.8...9.3.10)
> 29 April 2018
- Release v9.3.10 [`bcac79f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bcac79f5605f9b1e5bf3a02fa3e10d17ceb544fc)
- Merge tag '9.3.8' into develop [`f1ba80a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f1ba80a55c288f1c9e99106f6ca64cc18edb589a)
#### [9.3.8](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.7...9.3.8)
> 29 April 2018
- Release v9.3.8 [`79bf6f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/79bf6f61d5c61d611441bb2eba0952187a936dcc)
- Merge tag '9.3.7' into develop [`8cc8b62`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8cc8b620f822731e4dc96cdbb4c9b87ef97acc9a)
#### [9.3.7](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.6...9.3.7)
> 29 April 2018
- Release v9.3.7 [`fd43837`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fd438372f2c3ecd85d855beb9c14bdecd1be370a)
- Code refactoring for backlog and daily searches [`26ab1dd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/26ab1dd3e9b231b1274355de9b775ed12b211a86)
- Pre-Release v9.3.6.dev1 [`3afe2b6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3afe2b6d8aa0b0dcb8da7570becf96cd7cb0c660)
- Daily searches hard-coded to search from todays date and greater [`37d5cd0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/37d5cd03336d1155965d10fb96999891a98a266f)
- Fixed issue with stuck current item in queue [`be6173b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/be6173b254f8b7886832e84f0f810288f76b4bdf)
- Fixed issue where cloudflare bypass would loop when unable to bypass [`40c2bce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/40c2bce256cc897790ecf8e050a4b6cd35d70c0b)
- Pre-Release v9.3.7.dev2 [`0d890f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0d890f1a07215ce69da5f24bb3186d8475cb8baa)
- Code refactoring for backlog and daily searches [`9f2aac1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9f2aac1b5c3b2f34452b8a7f2e350018df4d25f8)
- Pre-Release v9.3.7.dev3 [`b9546e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9546e2c823a931243362f15f9bab6c212f3acfb)
- Pre-Release v9.3.7.devNaN [`7b8402e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b8402e4bff048a73338f2da1f86f6f3591dabb6)
- Pre-Release v9.3.7.dev1 [`f77cf2d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f77cf2da65de31a0ee847e1ba668bf9b9ed0111d)
- Merge tag '9.3.6' into develop [`db2d8d0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/db2d8d0b7a252ac1da697c41d77e1428a848a8f8)
#### [9.3.6](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.5...9.3.6)
> 21 April 2018
- Release v9.3.6 [`ee7b8bc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ee7b8bcd28dd215c332a430ac684862ff8dad070)
- Backlog searches no longer trigger cache updates, speeds up searching [`04cf1ef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/04cf1efe6da932297a0fce1811f9bbed9313be3d)
- Manual searches and Removal of shows now take extreme priority in queue [`aa08e0c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aa08e0c368730cfc37fd4913288ae3f8f6c736eb)
- Daily/Backlog searches now skip downloaded episodes with higher quality then show's set preferred or best. [`c32702b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c32702b0fb9e099579fff0efa42987cbc8ea42ab)
- Manual searches and Removal of shows now take extreme priority in queue [`b96a3f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b96a3f9ea7ff9daf29baca3a6f0699a09200d3d8)
- Manual searches and Removal of shows now take extreme priority in queue [`9e76bc0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e76bc0a0a5d34d7ed3bac473a405c5b7ba98bea)
- Manual searches and Removal of shows now take extreme priority in queue [`a7210e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a7210e46cb4799723e9c902db8bf9322ba1b83ac)
- Manual searches and Removal of shows now take extreme priority in queue [`e8cea87`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e8cea87b0eb47c706900ca2d91a233ebd389998d)
- Merge tag '9.3.5' into develop [`fbdf6f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fbdf6f9fb05f8c7b85d38fbd48e9c34da146d1da)
#### [9.3.5](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.4...9.3.5)
> 10 April 2018
- Release v9.3.5 [`57b8a79`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/57b8a7922b29693dc07d7972036064f1bf1e2f15)
- Merge tag '9.3.4' into develop [`c5476b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c5476b38f539467b1c7cd3a6371ee2a5ba8be70e)
#### [9.3.4](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.3...9.3.4)
> 7 April 2018
- Release v9.3.4 [`c056018`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c056018b1002d12ae4bca8518f27978b670b6db5)
- Resolved issues for post-processing already processed compressed files [`a5e76f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a5e76f4b1a5007af257a74128b74f83edf61f99f)
- Merge tag '9.3.3' into develop [`e4a0cac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e4a0caca812f27ad4fee0f9fed68fa922717a6f6)
#### [9.3.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.3.2...9.3.3)
> 27 March 2018
- Release v9.3.3 [`8c8feea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8c8feea039d0b41dcc5ab7ba342c5b0e1183c87e)
- Fixed issue #187 - Qbittorrent failing authentication [`b6885a5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b6885a5d3b95ad387dfffdceec958c11c9d1c39a)
- Merge tag '9.3.2' into develop [`9c4ff81`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9c4ff81be2ae93420873dae10d5d16fea0b3fd33)
#### [9.3.2](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.101...9.3.2)
> 21 March 2018
- Fix call to generate_bwlist on save [`#9`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/9)
- Release v9.3.2 [`f546064`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f546064ed7ae9a67e0659e00fe3fe2b1919bef89)
- Minor code update for provider cookie handling [`98fa8b8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/98fa8b849b57d810eae2aee5805ab847f1048976)
- Fixed issues with cloudflare protection not being detected [`23df733`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/23df73395afc276cc39417670bf1910cf27ca654)
- revertFailedEpisode changed to use debug instead of warning for episodes without previous snatched statuses [`54cc664`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/54cc664f0d207b5080e4bd93e2098021933a82fe)
- Fixed small typo in daily searcher code [`e0fa39e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0fa39ef348c2e24a4be843e073684698835d1a4)
- Fixed small typo in daily searcher code [`cc43195`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cc43195a81e2c96e01522b13c435eae3e5e2570f)
- Updated .gitignore [`fe0d03b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fe0d03b2980e3e37394274a47b2fd5f771eeb50c)
- Merge tag '9.2.101' into develop [`64d1dcf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/64d1dcf3cbd658adf1f8df0ede7dc771053dbcfe)
#### [9.2.101](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.100...9.2.101)
> 8 February 2018
- Release v9.2.101 [`aa7292f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aa7292f10a8590f923c3d280087e1c990abc363f)
- Fixed issues with backlog and proper searches [`c94ad9f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c94ad9f4481a056c9a704ee875becb565a7269e7)
- Fixed issue #176 - autocomplete colors when using dark theme hard to see [`b608667`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b608667834b1b228a5fe1efade0e590e1ba05f5d)
- Fixed issue #176 - autocomplete colors when using dark theme hard to see [`e73b9af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e73b9afd5226b719e0152dee2e74cb0c93fcf1b8)
- Fixed issue #176 - autocomplete colors when using dark theme hard to see [`e77ea77`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e77ea77e99f716e731dd7181e4818815e5767016)
- Fixed issue with next airdate and main show page [`c912546`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c91254644468ee85e703fb9c72510c300b33ec12)
- Fixed issue #177 - case-insensitive sorting for drop-down show list [`372b59e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/372b59e4ffef6050ac0c19d35e4f69ec06a7f464)
- Fixed issue with next airdate and main show page [`f50e104`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f50e104e4f339f74ac2f4650a025ed6b8a4aabb6)
- Fixed issue with next airdate and main show page [`e9494a7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e9494a7b959255dab3b312aae43b55fd754597cb)
- Fixed issue #175 - autocomplete "Enter the folder containing the episode [`2c89486`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2c8948673931a75cba6d61ada820f5b4072907de)
- Merge tag '9.2.100' into develop [`c0cde58`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c0cde58f4957e6b8393006ed8183078ece1b6875)
#### [9.2.100](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.99...9.2.100)
> 31 January 2018
- Release v9.2.100 [`c5bee33`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c5bee33a32d22f60d0d4f14a06ceaa6ccb2d543d)
- Fixed issue #170 - double popup on hover over network in show list [`c91e143`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c91e143363c90de07ccb8466c9e477f6a9bd3719)
- Merge tag '9.2.99' into develop [`de1b8fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/de1b8fe0c86877b63378380112c9ebd660189859)
#### [9.2.99](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.98...9.2.99)
> 23 January 2018
- Update torrent9.py. [`#7`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/7)
- Release v9.2.99 [`dff6cff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dff6cff14c5ad0258408c45d536b0f011caca402)
- reverted requests['security'] to requests requirement, was causing issues for synology devices [`d076678`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d07667815b5b2cb4a5e0dc4d37eaccd7c8edf76a)
- Merge tag '9.2.98' into develop [`d7b68b6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d7b68b638ce3c4e284d823a3b2876dcf111a6210)
#### [9.2.98](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.97...9.2.98)
> 20 January 2018
- Release v9.2.98 [`016ec81`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/016ec8165aeb1f155e5660386373926ff72e6dd4)
- misc range to xrange changes [`0ebcc19`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0ebcc1961bf37968450a46d7d3f3d89053a3e199)
- Fixed missing token error [`927c3c0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/927c3c0d10cd981225c9641cb388cc9cbd490e22)
- Fixed missing requests security requirement [`b8fabca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8fabca0c3a51a973ab8b69f5fbd7440c0060bd0)
- Merge tag '9.2.97' into develop [`3c3f2c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c3f2c76a29c2899c653b607f56ba5f70e88fed1)
#### [9.2.97](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.95...9.2.97)
> 18 January 2018
- Release v9.2.97 [`7cf97c1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7cf97c114264fe46e75b327ad6b7cf15ddb5fe5f)
- Merge tag '9.2.95' into develop [`3d4a008`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3d4a0080aa44a60414024026614b5db8f5b8dac2)
#### [9.2.95](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.94...9.2.95)
> 15 January 2018
- Release v9.2.95 [`b8ae4e8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8ae4e83ddc79e722575a92ba74735a1d0b6b0e8)
- Fixed issue #167 - PreconditionsException when saving IMDB info [`70d1ecc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/70d1eccc4eba0f0aa3f3785a5b2c663af54efb5a)
- Fixed issue #169 - Missing parameter: "refresh_token" is required [`0817995`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/081799575c2bf93e2c44506eb10649a89b3be04f)
- Merge tag '9.2.94' into develop [`b882ef1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b882ef1cc400b56ef987881752c8f78c4b0a2f9c)
#### [9.2.94](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.93...9.2.94)
> 12 January 2018
- Release v9.2.94 [`4931383`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/493138316a8b9c8f41b0371dec3c0288c81f0f45)
- Merge tag '9.2.93' into develop [`5d7c0ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5d7c0ba570ea62ff4b84b6bf3aece3c6a0a5a0da)
#### [9.2.93](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.92...9.2.93)
> 12 January 2018
- Release v9.2.93 [`deedce0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/deedce044df20a09e8e109ad6ee4704301c36eb9)
- Fixed issues with refresh token when using client credentials [`2af9433`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2af9433efafd46be36fcdf41c1909c2188e059e0)
- Fixed issues with refresh token when using client credentials [`c9449f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c9449f938fdcae68d8ce58e9b965210b38b775c6)
- Merge tag '9.2.92' into develop [`2f72882`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f7288240d52483ab534f23f87080da8a9373032)
#### [9.2.92](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.91...9.2.92)
> 12 January 2018
- Release v9.2.92 [`dae404d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dae404d8b2b9cea85a26c4b0872644c41af58a47)
- thread name added to UI warning/error messages [`8bbd2b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8bbd2b2e63ae9b7135b01f7c8908b18827eb4619)
- Updated requirement psutil from 5.4.1 to 5.4.3 [`b48dd3f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b48dd3f1531bd4276c7012eb9b11dbe4cb509b30)
- Merge tag '9.2.91' into develop [`3a2cc77`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3a2cc77b88f749940b28fcfbb5dc60c2421b6787)
#### [9.2.91](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.90...9.2.91)
> 7 January 2018
- Release v9.2.91 [`1c36a65`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c36a65f80cd8aa51914f317b4a788e3c6288c05)
- Fixed issues with air-by-date shows not properly being parsed for episode numbers [`8cdd6f2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8cdd6f23d0c3940a5b48a9d345a91873aded90a1)
- Merge tag '9.2.90' into develop [`ec51e1a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ec51e1aff290f2c85ae29d3cae15634335160ad7)
#### [9.2.90](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.89...9.2.90)
> 4 January 2018
- Release v9.2.90 [`17ae529`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/17ae529ed59ab7ba04d62bc70d0a7a79c3c027e5)
- Merge tag '9.2.89' into develop [`94c04e8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/94c04e8fc14642dbc584adf07a9e4c1cf3ff3499)
#### [9.2.89](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.87...9.2.89)
> 4 January 2018
- Release v9.2.89 [`6d49779`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6d4977973a2b1913d60adefc830f9b3d37c493e0)
- Fixed __getitem__ error for managing episode statues [`3a38155`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3a381551601b9a1a93d5578725ed1333199c1037)
- Refactored restart template [`5e417d2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e417d24a1bf97ee7c2b05be638ee285cbdd509c)
- Refactored restart template progress bar to increment by 1 percent [`81ded5d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/81ded5d444e51f0786fa35f8740c34bc146c3dfa)
- Updated imdbpie requirement to v4.4.2 [`5a2f6c5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5a2f6c55a8545cbbe6fcd642e1c5f152fbb5399b)
- Refactored restart template progress bar to increment by 1 percent [`1e25dae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1e25dae34e7da338986516637b777ccb046e4a0a)
- Merge tag '9.2.87' into develop [`4c14747`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4c1474786989eb5b02e11a78f674f7c297af202f)
#### [9.2.87](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.86...9.2.87)
> 26 December 2017
- Release v9.2.87 [`975d890`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/975d890f93135293e40c2dfd4187847713c72ff0)
- Misc cleanup [`15ec220`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15ec2204a517486d61a18718112f44eeb8554877)
- Merge tag '9.2.86' into develop [`1de214c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1de214cb5bc5d8862b066462a3ed321967c7f4c4)
#### [9.2.86](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.85...9.2.86)
> 25 December 2017
- Release v9.2.86 [`1475c1b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1475c1b7a1cdcbaa0e40d0fa4ea1b23e8ce2728a)
- Merge tag '9.2.85' into develop [`224a5e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/224a5e12dcc8b3503b0b3a421603307e68546e89)
#### [9.2.85](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.84...9.2.85)
> 25 December 2017
- Release v9.2.85 [`a5944f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a5944f11b106a0c90b3b21d74ae57913f4b31479)
- Refactored restart template to be bare to avoid template errors on updates [`4c548b6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4c548b623cc8379ff3882bc6cd4ec23a66002dcc)
- Refactored changelog to modal popup window [`552c936`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/552c9363af05b27ef232135eb1789dd156236b26)
- Refactored restart template to be bare to avoid template errors on updates [`1b9b39a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1b9b39a65dbc34e3d0695cccd08642a4bfb90cff)
- testing changelog viewing [`cd76821`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cd76821a11f68e8e2cb270a99c2a2da42307aed2)
- Merge tag '9.2.84' into develop [`ec666d8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ec666d8e06e4420123704dba39b284a20f41610d)
#### [9.2.84](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.83...9.2.84)
> 25 December 2017
- Release v9.2.84 [`ced2fd5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ced2fd54646de405208f43c066e3ff06f87c4e40)
- Merge tag '9.2.83' into develop [`2f212c6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f212c60a49fad0473f97fce3f03280ccd23e566)
#### [9.2.83](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.80...9.2.83)
> 25 December 2017
- Release v9.2.83 [`bf259dc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bf259dcaee1005f8e7ec61374c2af7735ffcbacf)
- Updated more requirements [`0032372`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0032372d2df8928a0b9b7ca53b5e09ecbf246b3c)
- Updated requirement imdbpie to v4.3.0 [`c73c554`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c73c554ba27395ef6393cf98a74b5d4a31598a09)
- Merge tag '9.2.80' into develop [`c5654c3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c5654c3342999129ce52e2d50fcd8a491d7376c0)
#### [9.2.80](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.79...9.2.80)
> 23 December 2017
- Release v9.2.80 [`b592d44`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b592d44951cf9be6e4980534b8f1438ceec834a7)
- Merge tag '9.2.79' into develop [`1f4c8a8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f4c8a83358277f66c9530ccaf8fe81cf34bdccc)
#### [9.2.79](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.78...9.2.79)
> 23 December 2017
- Release v9.2.79 [`f8908fd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f8908fd062b08b9d007039e6b47ea589bf2d370c)
- Merge tag '9.2.78' into develop [`a62808d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a62808d8ae2fb5779d8d6add0fcff4eed9d8faf5)
#### [9.2.78](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.77...9.2.78)
> 23 December 2017
- Release v9.2.78 [`484002a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/484002a2f7c0d0c123ecaa9451cb8d7b1a71d2ea)
- Merge tag '9.2.77' into develop [`643d44e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/643d44e95bd66fbd7f22910f55f4b5c048668855)
#### [9.2.77](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.76...9.2.77)
> 23 December 2017
- Release v9.2.77 [`5439184`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5439184faa7f332a0f827c288993e693daee4f3a)
- Merge tag '9.2.76' into develop [`2657da2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2657da2451530a85cbae86992c992ddd21b17cf8)
#### [9.2.76](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.73...9.2.76)
> 23 December 2017
- Release v9.2.76 [`d1d0033`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d1d0033a73595df29751e7dc8b862bc1b75bcfa5)
- Merge tag '9.2.73' into develop [`d7764cf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d7764cf4ad6e85be60d423190c5400f78db8195b)
#### [9.2.73](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.71...9.2.73)
> 23 December 2017
- Release v9.2.73 [`bad836b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bad836be8b2a9f1fcaa793d630fbd2ad76186acb)
- Merge tag '9.2.71' into develop [`3c59887`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c59887ed675d51303e78d47c178de1c31d2f970)
#### [9.2.71](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.70...9.2.71)
> 23 December 2017
- Release v9.2.71 [`0eaf7ee`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0eaf7eea2a948a88122956d514f3a29de283f1b2)
- Refactored core js code [`9dce9e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9dce9e45836819ebd784413c33bc92729cb32b42)
- Merge tag '9.2.70' into develop [`9f2d905`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9f2d905ccd1d946b622fe435f5bf42ca8c20e28c)
#### [9.2.70](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.69...9.2.70)
> 22 December 2017
- Fix for torrent9 provider [`8ca1761`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8ca1761ef40cdb019b7866864cd5e71158743837)
- URL validation for provider search results added in to code [`c1e9c48`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c1e9c486bfe8df97f3e1206e07808e9e40ac0e5e)
- Release v9.2.70 [`d41046a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d41046ab0394348e82ec03cd3868f6d607fbdd93)
- Fixed issue #155 - version updater bar not showing [`d07716c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d07716c031de0e664ec47aec5aa5b307a788e1c5)
- Fixed issue #155 - version updater bar not showing [`a022118`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a02211827de5a0e3cd31284b3a89e777b1599b09)
- Merge tag '9.2.69' into develop [`ebc535c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ebc535c1eca44b244ff6e9023213cc69c04d9783)
#### [9.2.69](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.68...9.2.69)
> 21 December 2017
- Release v9.2.69 [`af0e32e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/af0e32e04d45b825376cdb1567990c7c1a9052e3)
- Fixed issue #159 - Error parsing provider newpct.com [`7733262`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/77332628337f9a08ce514e408e0c0132b81ee70c)
- Fixed issue #159 - Error parsing provider newpct.com [`7dcd312`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7dcd31271022465d3073776efb0f5f287c9a8f15)
- Merge tag '9.2.68' into develop [`684716d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/684716d6a4669f6c0c151c5089f7a0846f621fbe)
#### [9.2.68](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.67...9.2.68)
> 21 December 2017
- Release v9.2.68 [`c3eb182`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c3eb182be68240807060db1e582ba2d3ca2ce891)
- Fixed issue #141 - show/hide seasons in display show page [`611ea99`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/611ea99e1c67c906900ad793b9905f4ee35222d0)
- Pauses background jobs while post-processing then resumes when finished [`def31cf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/def31cf3bd6785efdffde6ae720c9818e2bc889c)
- Refactored cache search function to handle multi-ep results [`7aa5593`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7aa5593001962d3e619caee6900917f4b50c61c8)
- Fix for issue #155 - display notifications when updates are available [`bf5179f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bf5179fc1acb476fed522251b3052e5b5aae0b71)
- Pauses background jobs while post-processing then resumes when finished [`52d9960`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/52d9960bf18bb92ccf629f090458c5dbdc387da6)
- Updated status page to work with new scheduler code [`19a9760`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/19a9760326e4ba40a24091d7b911402bfdc8f9d2)
- Replaced main loop with IOLoop [`e3f5f76`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e3f5f762044487cbb890592e4db6146db5e66ffc)
- refactored post-process variables [`328e9d8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/328e9d85eaf571559f4d18d1bf779217f06f0cba)
- Replaced main loop with IOLoop [`3bc75b9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3bc75b90213f88c611bf63dc6b28df16d4aaaa4c)
- Pauses background jobs while post-processing then resumes when finished [`9e6831e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e6831e3de94b3f182be4bd93c1217b0281270cd)
- Pauses background jobs while post-processing then resumes when finished [`ba50828`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ba508285e347fb2746ff0efcb0bf7ea8767b1c91)
- Fixed IOLoop to use current instead of instance during init period [`cea3a5e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cea3a5e556b05f3fbb226df997e56594e146f6d4)
- Fix for issue #155 - display notifications when updates are available [`16a7332`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/16a733282980d1b56c0e1b6f5d93f2dce8fcd414)
- Merge tag '9.2.67' into develop [`ce10150`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ce101505ce9f7cfb336225843bc06abd1bcb1dcc)
#### [9.2.67](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.66...9.2.67)
> 17 December 2017
- Release v9.2.67 [`3b4302a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3b4302abcaa3f08962cae0d93fc8037ac2ee68ab)
- Merge tag '9.2.66' into develop [`5649d4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5649d4b990f8c5c473cb36045d1d07f60f90fd9f)
#### [9.2.66](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.65...9.2.66)
> 17 December 2017
- Release v9.2.66 [`5f48f83`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5f48f837a16b68b15a5a516b3c94510326c8d87c)
- Fixed issues with unrar and windows platforms [`313d7fd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/313d7fdba97c7449dd775156b3e3dad9aea251f4)
- Fixed issue #153 - Checking delete files when removing a show didn't actually delete the files [`7682ad1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7682ad1cb1cad372f8e57741ddf7aeaa24570f3b)
- Merge tag '9.2.65' into develop [`40fbb92`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/40fbb92a38d47e4be2fbf1c6cba563a23ab8a94f)
#### [9.2.65](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.64...9.2.65)
> 16 December 2017
- Release v9.2.65 [`3c60c67`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c60c67e009bfae9ec47920d01c4e2076256d1bc)
- refactored torrent cache api calls [`1c5d901`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c5d90188aaed7430abc1512cc996d59ea9d76ab)
- Fix unicode issues for Newpct torrent provider [`bb8a5b8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bb8a5b8a31728e7fb8e4c8ede5316b8bff2167f3)
- refactored torrent cache api calls [`e5ee3a3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e5ee3a32a69e7c15279111764a7aa5ec5308f16d)
- Fixed url issue [`d53ccb0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d53ccb0c81c01bf9808d8d92a6b8d86541d51051)
- Merge tag '9.2.64' into develop [`774a253`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/774a25363d7e0355664266284fc1d169cc877787)
#### [9.2.64](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.63...9.2.64)
> 15 December 2017
- Release v9.2.64 [`032e9ed`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/032e9edff5cfcb51e665b7712fc472be080a6730)
- Merge tag '9.2.63' into develop [`e6b8105`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e6b81056ebec09df5376c4b59cce7bb2f928e2b9)
#### [9.2.63](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.62...9.2.63)
> 14 December 2017
- Release v9.2.63 [`9d35ea1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9d35ea1b11b05bbac29756d48019d7d486080e9d)
- Merge tag '9.2.62' into develop [`c24bfcd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c24bfcd456b3f99d681fd0e8a6c222999a881bb5)
#### [9.2.62](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.61...9.2.62)
> 13 December 2017
- Release v9.2.62 [`20416e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/20416e1b54816992410f1476073d45e87f682346)
- Refactored database calls, resolves memory usage issues [`4323d84`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4323d84486972a8de38bec1e20bc31a9a6f441d5)
- refactored remaining database calls to use custom database calls [`3f23fd2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3f23fd2ba9b84436b5163f9a60d139ff64ea6580)
- Fixed issues with failed and cache database md5 checksums [`8923500`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/89235004066fda4e8443148dffc899fbba2f51c5)
- Fixed issues with removing duplicate shows and episodes [`8e43de8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8e43de8936695c121f1efde28eeb056be06ccba6)
- Updated misc provider code [`7b19a3c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b19a3c99e3f0a2e6293e240898ac573fc167716)
- Fixed issue with thread naming for post-processing [`2c6c207`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2c6c2079370b995c29b362dea0d7ca1b3944cd57)
- Fixed issues with failed and cache database cleanup on new revs [`93c5ad5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/93c5ad51ec23ff27dd8fe4bc2569754cbd26d366)
- Fixed issue #151 - using unicode instead of str to result post-process results [`cf0821c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cf0821cde9679e27c7b105b815bf244e2931f79f)
- Py3 compat for queue [`b922499`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b922499a44be30abce4b789c76aae99d7a3780c5)
- Merge tag '9.2.61' into develop [`db0e196`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/db0e196bdb4d7d55ffacb2334b29976dafc34260)
#### [9.2.61](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.57...9.2.61)
> 10 December 2017
- Release v9.2.61 [`f2d7dc6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f2d7dc6a2139cd3b1b4b18749c85e2ffcbd1771b)
- Overall stats now only displayed for main shows page, helps reduce overhead [`656a038`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/656a0382816a635a7efc2fbb5011779bf83e6c95)
- Merge tag '9.2.57' into develop [`33f6d48`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/33f6d48ab308283cb88d65118acc2232ad3665cf)
#### [9.2.57](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.56...9.2.57)
> 10 December 2017
- Refactored Full Update function to now update/overwrite existing metadata [`f376394`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f376394afeb846230373e23e5b5431428d6ea205)
- Release v9.2.57 [`75fa296`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/75fa2966d5f22ee4234f755fdae5dea5c21d6724)
- Updated git ignore file [`9596e8c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9596e8c6158bf4a25aefedfdbeafe3db643ba708)
- Merge tag '9.2.56' into develop [`71895b0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/71895b0949d77ca056a17d689151688d9d750f34)
#### [9.2.56](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.55...9.2.56)
> 10 December 2017
- Fix for name parser anime issues [`f2405ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f2405ba0a015096254311101149ebe90844374bb)
- Release v9.2.56 [`2cd63ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2cd63baa48ca00b51ab22e901c7f5d1904a9c8ce)
- Merge tag '9.2.55' into develop [`9f644cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9f644cb34583bfb3546bde0ca0600b402a8c24f3)
#### [9.2.55](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.54...9.2.55)
> 10 December 2017
- Release v9.2.55 [`73ff883`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/73ff8835752ff9f97684ffe13673fd915bf9cb80)
- Merge tag '9.2.54' into develop [`aa883bd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aa883bdb3d34dd0afe5e2f1021eac5859b81d00d)
#### [9.2.54](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.53...9.2.54)
> 10 December 2017
- Fixed name parser show validation issue [`0728a1e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0728a1e00c5bd7d6a2e48d99ba1e1d810cde8a34)
- Release v9.2.54 [`d4b4aab`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d4b4aabd3b5fd4dc69be8e5cd968d2fdb82df43b)
- Merge tag '9.2.53' into develop [`9173003`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9173003ba04d26ccc49e46cf35fd4bcf178d06df)
#### [9.2.53](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.52...9.2.53)
> 10 December 2017
- Release v9.2.53 [`e096f6c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e096f6cc841ab116e5ed8b75973d71310367ea9e)
- Fixed issues with name parser and naming patterns [`750a56d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/750a56d9d70bbfa0a54fcda78444e8300f694e44)
- Merge tag '9.2.52' into develop [`d4bf567`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d4bf56740e0eaa2a6ee70f3091010af34a5385b4)
#### [9.2.52](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.51...9.2.52)
> 10 December 2017
- refactored nameparser function get_show to be more efficient [`f0d6a3c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f0d6a3c65b507dd637af2ffd6aa367066e293b9b)
- Fixed name cache, was incorrectly loading database info [`96f7a4f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/96f7a4f24f17d237eb789c93b4d95675d6ef6089)
- Release v9.2.52 [`4346486`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4346486fb81f92b11d204ba4114a6584402d937a)
- Merge tag '9.2.51' into develop [`5653abe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5653abe2f506ab87bb2a932180e41f29150afebe)
#### [9.2.51](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.48...9.2.51)
> 10 December 2017
- Fixed issues with HoundDawgs torrent provider [`5faefa1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5faefa19a96ef388c896ed710f3618c69ab8ed30)
- Fixed issues with validating search results from providers [`6493584`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6493584a5c5bbb2e241a4b9a069e81fbff4dadfa)
- Release v9.2.51 [`f893d27`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f893d27e33b349a3d56e11696aae0d8d0b08bca1)
- Fixed issues with validating search results from providers [`895ef68`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/895ef682a3f05e3c13289179f90d4529e00e063c)
- Merge tag '9.2.48' into develop [`3b1e211`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3b1e211d2df71b726c560adec636248a5d98dcc3)
#### [9.2.48](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.47...9.2.48)
> 9 December 2017
- Release v9.2.48 [`2626c5e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2626c5ef91edc82b073c42eecc0f5d71297c4ffb)
- Merge tag '9.2.47' into develop [`761162d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/761162d70a35bb352a85683603e62c1921f29b6b)
#### [9.2.47](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.44...9.2.47)
> 9 December 2017
- Release v9.2.47 [`654ae73`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/654ae739658bd7b6dc1a6f4bae4979dec653b38c)
- Merge tag '9.2.44' into develop [`cfac40a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cfac40af498c831de21877f6b682d43f771304b9)
#### [9.2.44](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.43...9.2.44)
> 8 December 2017
- Removed get_files function from providers to stop hammering provider api's [`01eb76c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/01eb76cba40029951e9f1492b944cd8b731a98ad)
- Fixed issues with make_url provider function [`e394ae7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e394ae752d4a9e02695e7a1701b08fc6ec90b69e)
- Release v9.2.44 [`d651b54`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d651b54300157a890e46beee7b49870817c9eeca)
- Fixed issue with picking best result [`59217e6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/59217e6cf20aaa13da9555d8b148eda27fbc998e)
- Fixed issues with make_url provider function [`acfef1e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/acfef1e12607c41cc76de3bb79376465b1212a04)
- Merge tag '9.2.43' into develop [`2d7217d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2d7217de758c90aa9bddca3063bbd2da4e12f5fb)
#### [9.2.43](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.42...9.2.43)
> 8 December 2017
- Release v9.2.43 [`bb5d189`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bb5d1896a6692a4c1a2fe68af01060a7c2b4fcc1)
- Fixed exception handling for post-processor [`2a9bb7e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2a9bb7e5cb14ceee920d23d4e1b0308d730d9f6a)
- Updated provider icons [`8de7690`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8de7690ada0450c41dcf2e21fb779ff89d6f1dc3)
- Merge tag '9.2.42' into develop [`e7e7ada`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e7e7ada6e617a11c465f8135d1abe2c52c042f5b)
#### [9.2.42](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.40...9.2.42)
> 8 December 2017
- Removed unrequired nextEpisode function as code was migrated into next_aired property function [`d1004fc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d1004fc7a6142d4de144734be8ed8d4e0862e0e7)
- Fixed issues with saving episode thumbnails [`78435a3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/78435a30fa41b7403245fa3ee8eea255b8117ec1)
- Release v9.2.42 [`d31018c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d31018c7dc56ebbc24731d7a9ec5bdca7c0d4b0c)
- converted bt cache url scheme to https [`7c1c460`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7c1c4605487d26d81f0990eb5c5d0a2ba93bdd8d)
- Merge tag '9.2.40' into develop [`c49a72b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c49a72b30701dd192440b994aa25f566c62c2bcf)
#### [9.2.40](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.38...9.2.40)
> 6 December 2017
- Release v9.2.40 [`9ba97d5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9ba97d537fd8f3a0cd8add0c78a6647c3dbe1130)
- Merge tag '9.2.38' into develop [`ccf8941`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ccf89419ce3fc9e55ddf4fdc9f9f568d18e79d58)
#### [9.2.38](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.36...9.2.38)
> 6 December 2017
- Release v9.2.38 [`5fdb6d9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5fdb6d93994d3688b2fd5c41b43df09420bfc064)
- Merge tag '9.2.36' into develop [`8bb08c3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8bb08c329837cd78bff26001442a0880a624dd6b)
#### [9.2.36](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.34...9.2.36)
> 6 December 2017
- Release v9.2.36 [`eb795bd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eb795bd6c16f470177a9e07d8466908f8d5055a9)
- Fixed issues with splitting shows and anime [`418d40b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/418d40b0fe8ed108383e78b7916c032d1f6b419a)
- Merge tag '9.2.34' into develop [`dacb36b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dacb36be513a9d4db1a0b7e2fa45f016f2756620)
#### [9.2.34](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.32...9.2.34)
> 5 December 2017
- Release v9.2.34 [`5b78ac9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5b78ac9b418834871fe709a23531d30a54c0de98)
- Fixed attribute issue when trying to manage episode statuses [`80e8622`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/80e8622555cf1da5eeffc6da6b951fab2150d219)
- Merge tag '9.2.32' into develop [`adf6f90`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/adf6f90b36da5466f2627e627d20ed4ea9b7d93b)
#### [9.2.32](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.31...9.2.32)
> 4 December 2017
- Fixed encoding issues with list_associated_files function [`b300f9a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b300f9ac36a8d63fd38b0925cef2e36048a13754)
- Release v9.2.32 [`e461330`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e461330a967048fd5b528521cbd69e2ade4ccd6c)
- Merge tag '9.2.31' into develop [`361b469`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/361b4691190ab007adc84c1c63850dc4e07deee6)
#### [9.2.31](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.30...9.2.31)
> 4 December 2017
- refactored elitetorrent provider code to resolve quality parsing [`ace1b62`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ace1b62cb59c184ec9fb17f28f2c41dcaa32426d)
- Release v9.2.31 [`c3626f7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c3626f7e7ae93111942051f277b845b3583c5f70)
- Merge tag '9.2.30' into develop [`fe70809`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fe7080954cf541449362dc3189b63e0da8554309)
#### [9.2.30](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.29...9.2.30)
> 3 December 2017
- Fixed typo in ComingEpisodes function, caused schedule to not display [`7e76b60`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7e76b6009f8d25547fb5bc1963e13aad06e76a59)
- Release v9.2.30 [`d3bdc71`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d3bdc71b3c1fde750fda02123cd7c4a634f82e4c)
- Merge tag '9.2.29' into develop [`acb8731`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/acb87310c708b808760bfd301f5f59249bff7c3b)
#### [9.2.29](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.27...9.2.29)
> 3 December 2017
- Release v9.2.29 [`c3e3a2e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c3e3a2ea6afb121de0271bfbd9045d88b012ce5e)
- Fixed issues with memory usage stats, added fallback code [`aa476aa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aa476aa5f6f04c53b21932d9d62edf6e1391d459)
- Merge tag '9.2.27' into develop [`a3d2faf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a3d2fafb03eb5f97a83e9e63dc79767acca57d3d)
#### [9.2.27](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.26...9.2.27)
> 3 December 2017
- Release v9.2.27 [`75c2b2d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/75c2b2d393166ac1e0ab98acb1f125e82d3c15fe)
- Merge tag '9.2.26' into develop [`20e3e66`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/20e3e66b81fb6f4f4277d10619c3f780f592c14f)
#### [9.2.26](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.25...9.2.26)
> 3 December 2017
- refactored xthor torrent provider [`56fe035`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/56fe035804994964d38bb6b62a2c561bf4deeeee)
- minor change [`3d55f82`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3d55f82f408746e4317fe80a2e8837d36812a8cc)
- Release v9.2.26 [`1f01aa0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f01aa0941f633e8c4f2852fb087021da9a3bfdc)
- Fixed maximum recursion error caused my new next_aired property code [`f7963ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f7963ce1d7111e3c800709bb7230f06eab67d566)
- Merge tag '9.2.25' into develop [`413b876`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/413b87620ec484351de9e70df511d8735ff75818)
#### [9.2.25](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.24...9.2.25)
> 3 December 2017
- Release v9.2.25 [`5bdf6f0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5bdf6f08155887beabb091898b72b60a3d5454e8)
- refactored core variable showlist into property function [`f66447c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f66447cbba66b17aec1b907813b51b5b7c0e48bd)
- replaced database calls to show table to use core showlist reference instead, faster lookups [`38e9062`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/38e90623cb8bf38e78cd52cac4aa1e99203257ed)
- fixed issues with returning help docs for internal api [`c61c9d9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c61c9d9796db8c2bd60eb2dc3bdffce10b44e790)
- changed donation url [`4ea708b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4ea708bb706d2bd41f753f1296b420719d9e39c9)
- Merge tag '9.2.24' into develop [`e483592`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e483592bfa04fa7a12541fc4d61bcbae86deacdd)
#### [9.2.24](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.23...9.2.24)
> 2 December 2017
- Release v9.2.24 [`98f1f5f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/98f1f5f96a4c029a043b0d60a3863f3a327a47ab)
- fixed issue with downloading unrar when saving post-processing settings [`586c52a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/586c52a576221e70eb939295258bb033cba3520b)
- Merge tag '9.2.23' into develop [`6beccb8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6beccb8304f87581229094f45763e42c116b45ab)
#### [9.2.23](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.22...9.2.23)
> 2 December 2017
- Release v9.2.23 [`8a5f8c9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a5f8c955c99eb561f321f2b515de7135665b83a)
- removed code for getting torrent hash from search results, no longer needed [`3783124`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/378312477e8d7cb4d167eebeecd145a80699aa51)
- refactored misc provider code [`2196912`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2196912c7ef03b4df36cbc730aae97a3b3bcb1c2)
- refactored api calls for built-in app api [`328e72e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/328e72e0396a3046fb59f6e16cac2220b23911c7)
- refactored provider test suite [`90cc105`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90cc105fafcc84b8fdf6fa5709ea8fc5a907c5e5)
- Fixed unicode issues for mass show updates [`88bd49e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/88bd49e8b812c6c9e1a2e066a27571348ae2c533)
- fixed issue #138 - sessions not persisted for verifying provider results [`76c748c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/76c748c841386c7753b08e6408f0b5f8f58021c3)
- disabled verifying private provider result urls to avoid excessive api hits [`bbd2f81`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bbd2f81376f843a1d2a56d79d0ae5e5fd4762ce1)
- Changed code to set app pid of fork when daemonized [`33496ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/33496ce5d0159406ff688b0d934680c802a1782c)
- disabled torrent9 provider tests [`a1d2e79`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a1d2e792aa3eef0cab66caf62a74509bca88506c)
- fixed issues with custom newznab provider api key being saved as int when it should be str [`7470b66`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7470b66ce690c6da2174d6dc08d473cb3dc2a98d)
- refactored docstring for api_calls function [`bfa12e5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bfa12e5dab286ef500277a498a65469723338dc3)
- Changed code to set app pid of fork when daemonized [`a7a3fbe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a7a3fbe01f57c15aa1f6f584584691e2cd41a2f7)
- Merge tag '9.2.22' into develop [`aa2a24e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aa2a24e303dba16d9fbd1d9e26a2d9c62e531dc7)
#### [9.2.22](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.21...9.2.22)
> 29 November 2017
- Release v9.2.22 [`9b332e3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9b332e35ada25ed673cc57071846e2c047a3d42c)
- Updated provider urls [`92818b5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/92818b51f1941f68151a8a004c709fafaa796d9d)
- Fixed redirect 301 errors for scenetime provider [`8164abc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8164abc441c42ea37b212aab52db0e89d0651c00)
- Fixed issues with provider searches validating shows during season and episode searches [`be06534`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/be06534288d9330038307719384139431df85bcd)
- converted input box to select box for setting failed snatch age [`8f29300`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8f2930088bdb639843229800597703bcf1ea6406)
- Merge tag '9.2.21' into develop [`2926d43`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2926d43a351b84fdc979b63d0f4904aab972ba5e)
#### [9.2.21](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.20...9.2.21)
> 27 November 2017
- Release v9.2.21 [`7d0057f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7d0057f976234c81b37b0882fc479c9e2a4209ff)
- Merge tag '9.2.20' into develop [`d12d9ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d12d9cae32a6b0afdac1d41ad345d63b4fab9ecb)
#### [9.2.20](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.19...9.2.20)
> 27 November 2017
- Release v9.2.20 [`5ce3b85`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ce3b85253116882cbaa37051669f93af89642a4)
- Merge tag '9.2.19' into develop [`aef462a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aef462a5dfe87b255038a1f9656386f1fe3c09fa)
#### [9.2.19](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.18...9.2.19)
> 27 November 2017
- Release v9.2.19 [`31c5977`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/31c59779bf6f00d8c8b0849e8ecf54d90b7168a5)
- switched to using poster thumbs for poster view on shows page [`7015df3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7015df300e764b7060d5cb1508c98c4940340851)
- Merge tag '9.2.18' into develop [`ded9dac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ded9dac21e4fc165b3e9686bb6ea65c37d3337a3)
#### [9.2.18](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.17...9.2.18)
> 27 November 2017
- Release v9.2.18 [`2028c51`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2028c51cd3248f081f5dea7b2911620cd3bbfdb2)
- Merge tag '9.2.17' into develop [`fe4ad21`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fe4ad21ae4e52d81103ff08fc8fa066f543f8ae3)
#### [9.2.17](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.16...9.2.17)
> 27 November 2017
- Release v9.2.17 [`3302be2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3302be2b45668153644dca82ac30f71fbe2d4b68)
- refactored misc function names [`0b308b8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0b308b83c85a6901367462c26a3c368fe40df22a)
- failed snatch handler now works correctly only for snatches 1hr old and no greater then 24hrs [`1554594`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1554594d834574acee065367976cc13d8da71f0f)
- check if instance is of list if not then make it [`35a929f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/35a929f9fdc7aa8a904782a887dbf98b18455856)
- fixed missing changelog_url attribute [`ba12e57`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ba12e57bf3d9cde3a1a1f89c018a50010d8cd031)
- Fixed changelog url issues [`a51d682`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a51d682633f7c4b1e35657209c08d9f8da6b918b)
- Merge tag '9.2.16' into develop [`ff39189`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ff39189d6bbedb0fa9e03a5eec06917c17e85ba4)
#### [9.2.16](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.15...9.2.16)
> 26 November 2017
- Release v9.2.16 [`f4f7da9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f4f7da9762df61f7160ce422bfa4f0e65945b0a6)
- fixed issue with associated file extensions view in post-process template [`95299aa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/95299aaebaaae60546ab6c10d6ecdeebf58192af)
- fixed up docstrings [`044fc10`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/044fc107fc894344fec4d545b16dcdb8fb314791)
- Merge tag '9.2.15' into develop [`931b7a3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/931b7a37fbe00ef45f158d5120e785af8e7c2f19)
#### [9.2.15](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.14...9.2.15)
> 26 November 2017
- Release v9.2.15 [`a75d9c5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a75d9c51b2d1d3c393073768369268a9a5cd5cdb)
- refactored misc code [`ec6f4c1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ec6f4c1eed6ab16508e30ff899afcab4438d967b)
- refactored misc post-processing code [`8929263`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8929263068396d801beee91ae1989ca4e5f36b8d)
- refactored failed download handling to no longer be a optional feature as its a requirement for failed snatch handling to work correctly, delete on failed is defaulted to false [`e6a9b5b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e6a9b5be8804c26d24ded2b640fadc3aee015c79)
- Fixed issues with removing non release group words [`5b66f09`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5b66f09df823a89239df9b6a250deaa2bad78d9e)
- Fixed issues for air-by-date parsing [`2480e26`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2480e26e30e4c944810f1e28b5705dd04b280847)
- misc cosmetic web-ui fixes/improvements [`9b8a71a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9b8a71aa4626a632aab79b5b82459b8cd308e12f)
- removed redundant "delete failed" option from search client settings page [`b2d5c3c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b2d5c3cf0993dd0cd1778d2f74ac43f7fb12d1a0)
- refactored misc post-processing code [`7666f8a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7666f8a8f391b033825a0a423edf7d269cff4966)
- Merge tag '9.2.14' into develop [`94a6098`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/94a6098cef647e8b6eb6c6997e6c3caeebf4e8bb)
#### [9.2.14](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.13...9.2.14)
> 24 November 2017
- Release v9.2.14 [`735e12a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/735e12a1f71b078df1045a8eb6b02368f4be9350)
- Revert "refactored config class updated config to v12" [`3da7164`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3da7164edae0bdd3cab9b671c04924cffbd8ebc9)
- refactored config class [`2722ee5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2722ee56072e155b9419b3c49fc310d04818d70c)
- added code to log episode id's to history for failed snatch handler [`70755c1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/70755c182e432e5c2c9ffff20fe5e2d93c49aaad)
- reverted logging episode id's for history, no longer needed [`11a9003`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/11a90039a08b6f3ab5a7f6b2bfbd02322f00bdd1)
- refactored config class [`630387d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/630387dea5895b445dd2c3bca560c1c7c20bfcd4)
- Refactored failed snatch handler code to use a tuple of showid, season, and episode for comparisons [`98a1036`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/98a1036052da9468fe7c95d3d366c320d29305ee)
- added code to failed snatch handler to skip paused shows [`093c597`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/093c5972999a8825d672fe1394bde3363d79a463)
- disabled failed search feature temporarily [`83ccdf9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/83ccdf962936811da30b5b6746a955a361ef48e5)
- Updated url for torrent9 provider [`cf00782`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cf00782950c789241272c894c941482a91cc986e)
- Merge tag '9.2.13' into develop [`ff496c8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ff496c895636431960c33b2d03dd3905e765f649)
#### [9.2.13](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.11...9.2.13)
> 23 November 2017
- Fixed issues with tornzb results containing magnetic links and searching [`2f1d94b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f1d94b70050226d4e4a7e982c3138a5997a3ac2)
- Fixed issues with Jackett search result downloading [`8d73c27`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8d73c275a4e2b637fc09d5af6cc8bfb1a461159e)
- Release v9.2.13 [`7132bf0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7132bf02cbb41370989cce9ca0570523be5c8b81)
- Fixed issue with IRC template [`e2a44f5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e2a44f5c5f3ac1c8193de7b22fae6911483b43c9)
- Fixed issues with Jackett search result downloading [`2e4eefd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2e4eefdc2e326b89b5fa29821057884a0618dd2f)
- Merge tag '9.2.11' into develop [`891e141`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/891e141d8fec7fffe14fba349c78d5f534bc2430)
#### [9.2.11](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.10...9.2.11)
> 22 November 2017
- Disabled validation of show names for refresh of show directories [`2c06e9a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2c06e9a1356fd5342a39a2ef0e13e6082939bdca)
- Fixed issues with custom newznab and custom torrent provider settings [`2fcac47`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2fcac47a2c1b2c7128190d1c2b768cb4b8e7da8f)
- Disabled validation of show names when loading episodes from directory [`3482813`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/348281301151e887cb24b6e500a47739056f051e)
- Release v9.2.11 [`b9a002e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9a002e4bf861138a8bcba0885ac15587836f85d)
- Merge tag '9.2.10' into develop [`73a4826`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/73a48263d8682591ef45a0ce8c63cff9186f6d2b)
#### [9.2.10](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.9...9.2.10)
> 20 November 2017
- Release v9.2.10 [`74297b9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/74297b98d7fc0d236baf87b60fc9ae003a5d23a1)
- Fixed issue#127 - timezone issues on Windows platforms [`b8da064`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8da064ef41d9a406696d4f9b22ab9cab6db6e2d)
- refactored backup function for app [`34ceaee`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/34ceaee9c7e8a76eb7d2ce503226a080bd8f197d)
- Merge tag '9.2.9' into develop [`a2cc0ed`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a2cc0ed1dcacb85759d7f40f7cdb871d513a87f8)
#### [9.2.9](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.8...9.2.9)
> 17 November 2017
- Release v9.2.9 [`c8d47ec`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c8d47ec3fc771fbc1f1042432f1bddcfab059cd0)
- Fixed index error during config backup on updates [`2d941ea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2d941ea743dc322f71df5e5d72f752ef6026531c)
- Merge tag '9.2.8' into develop [`dda0777`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dda0777d578fedfdffc76473e055b95a461c5aca)
#### [9.2.8](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.5...9.2.8)
> 17 November 2017
- Release v9.2.8 [`23af894`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/23af89480751522b8ae5b6c4440243839bc1d756)
- Merge tag '9.2.5' into develop [`b4bc161`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b4bc1614cdd761fada08b491713b81943007933d)
#### [9.2.5](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.4...9.2.5)
> 15 November 2017
- Release v9.2.5 [`019c736`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/019c736ad6145550a2a97518e516eedc1d2e9e27)
- Merge tag '9.2.4' into develop [`c0c3793`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c0c37931f3164eb822eeefd42b419c0c9e4b0810)
#### [9.2.4](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.2.2...9.2.4)
> 15 November 2017
- Release v9.2.4 [`ab16911`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ab16911f83e04b00d6a9b5319a6c07df0dbf70c4)
- Cleaned up provider template for newnab providers [`0ba5a22`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0ba5a2290e0f0d0e76fecf7c90a856bd39dd337b)
- Merge tag '9.2.2' into develop [`c988625`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c988625d09e9ac5ac51388af729a443c89e915b6)
#### [9.2.2](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.78...9.2.2)
> 14 November 2017
- Release v9.2.2 [`a1f1730`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a1f17307915a82d7800701cda722a5fdd9d3a28c)
- Merge tag '9.1.78' into develop [`9d7a7d0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9d7a7d016dff6be802f569ba1ba053e9db671852)
#### [9.1.78](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.77...9.1.78)
> 14 November 2017
- Release v9.1.78 [`0505c4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0505c4bc93756f3b37f925e50732a71688471218)
- Merge tag '9.1.77' into develop [`f5abd06`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f5abd06415cec910789728d0d49e74e4586b9fa1)
#### [9.1.77](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.76...9.1.77)
> 14 November 2017
- Release v9.1.77 [`89810e3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/89810e31b8fad58da51f8d90cf885e7cca1405ae)
- Fixed subtitle tagging for Newpct provider [`2163b57`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2163b57048a343c927cedc335e466f0277f75fed)
- Merge tag '9.1.76' into develop [`1f0c981`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f0c981510aa113a0ef38a252b209f5dea73ce18)
#### [9.1.76](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.74...9.1.76)
> 14 November 2017
- Release v9.1.76 [`2425b4c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2425b4cdbf87029a2d71ef2123023de23a3f5be8)
- Merge tag '9.1.74' into develop [`0003335`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0003335ef52e7a07f97319b8222921f00ab7558a)
#### [9.1.74](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.72...9.1.74)
> 13 November 2017
- Release v9.1.74 [`f1a6e69`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f1a6e69144a486dd8f82c294b4f48bcfde20f758)
- Merge tag '9.1.72' into develop [`d088d31`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d088d310ef0d52ce8959358b5c437fdaefb827f4)
#### [9.1.72](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.70...9.1.72)
> 12 November 2017
- Unidecode Newpct titles to avoid unicode issues during name parsing [`0b32673`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0b32673641f0fdb300d2d6bfc16e250599f08dc2)
- Fixed search issue with Newpct torrent provider [`1c854a2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c854a26c74310300199026846d508d84883a892)
- Disabled external caching of private search provider results [`c98575b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c98575bc3330efc1cc1df4cb23a7d12f5660a807)
- refactored providers [`342df0e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/342df0ed8e69a87031f59536e9fe79f781885a14)
- Release v9.1.72 [`15e1861`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15e1861ed8e9d0907b978bb498fc753ab27bc8e1)
- Merge tag '9.1.70' into develop [`f6c0895`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f6c0895b708382e72387a7cc4c7eeee2ef6fecbf)
#### [9.1.70](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.69...9.1.70)
> 10 November 2017
- Fixed typo in code for daily searcher [`9498449`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9498449465805f6a5e56f75bc73c41c0cada8138)
- Release v9.1.70 [`24e1037`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/24e10375b55cb97cc30261e01b4ae6020b712977)
- Merge tag '9.1.69' into develop [`4c53c90`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4c53c90a95c69eac367333c0d7099b11535f550f)
#### [9.1.69](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.68...9.1.69)
> 9 November 2017
- Release v9.1.69 [`b26010a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b26010ab6c391967e054f35eaa437c9ef2c88f51)
- Decreased time it takes to search with Newpct torrent provider [`718179c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/718179c178a10b5d6fda2afe16298d6eccada117)
- Fixed issues with displaying correct show quality when editing a show [`9349846`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/934984677a12a730562d85ed9992459cd53483b2)
- Fixed typo for server status template [`e0c1882`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0c188204d4067c857452267019a0f782dacc0d3)
- Removed all but itorrents bt cache provider [`725ea95`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/725ea953f8422ca8479aac7f1738783878918f57)
- Fixed typo for server status template [`fe471c0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fe471c040745244c0d411546ec55ab76a3ab08b2)
- Fixed issue with a bt cache url [`58564e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/58564e197a04a3b4e9589cf8e4c44610e57efe72)
- Fixed issue with a bt cache url [`f2ba6fa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f2ba6fae875dea8196c96b8d3958f65e9f41ee6b)
- Fixed issue with BitCannon torrent provider [`27af54e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/27af54e58c5ad3f4311794b5b317f276591cceaf)
- Merge tag '9.1.68' into develop [`c7de9a9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c7de9a977617be5b019d504cead78d7e18ddf550)
#### [9.1.68](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.67...9.1.68)
> 9 November 2017
- refactored Daemonize class to use os exits when forking instead of sys exits [`eaf2a97`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eaf2a97673a2df07ce4892f0602f9eb9c333e80c)
- Release v9.1.68 [`1970e1d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1970e1dd8d29f987af9ba86edbcab548533df37c)
- Merge tag '9.1.67' into develop [`36eb27f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/36eb27f552d2380b5ca1e7b556ab9b340354dff9)
#### [9.1.67](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.66...9.1.67)
> 8 November 2017
- Release v9.1.67 [`1a61bc4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1a61bc463c3627806476294b7a1a18ca1c434536)
- refactored variable name srCore to app [`bbe7773`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bbe7773e6c0d1b76b4297944a58aaa729372ef87)
- refactored core config instance variables [`73ee12e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/73ee12e595ff73c950d1955bbc7d7726038be812)
- refactored core variable name srConfig to config [`e18ac02`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e18ac02bc5a400f6365340ef29fb3218bfec88e4)
- refactored core variable name srLogger to log [`cf804d2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cf804d240dbd24d5ebf2fab8e79d1ffe14f9aa6a)
- refactored core code relating to instance variables [`b407d9c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b407d9c881c1344e0e1ff8b058c3e5031ef97c96)
- refactored core variables from main module to core class [`83efbc5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/83efbc5b23823808a985b8c968880e10384b1887)
- refactored core code relating to providers [`30c56e0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/30c56e04f764a854a06b519cb86d428f96413b42)
- Decreased app startup time [`325ab75`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/325ab754a3b9633069181281bdb5a25195ac17b0)
- Fixed issues with posters overlapping on show list [`5127668`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/512766899285b80bf8948d672376d2a57ec02e53)
- Misc typo corrections brought over from previous code refactoring [`a6240ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a6240ce906aa7ec0ffe53606f4932b66e7f5ec0a)
- Updated bt cache urls and method for verifying data from them [`53aa1b8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/53aa1b8dad9e35ddfc3350b9d33c9ac7f589d63b)
- Fixed bad reference [`90b402d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90b402d83bfbee9d2b571631806617e32e429ea0)
- Fixed issues with verifying torrent metadata [`5d18ffb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5d18ffbbd124838ad6e3490a05747ecb2ef4f1f3)
- Fixed issue with daemonizing and pidfile's [`5cca270`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5cca270b76ff5624e45a84b9c2cffe11d18bce4c)
- Fixed issue with Newpct torrent provider skipping first result from search results [`9221129`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9221129241b10eb7cc750938d1cc69464a421473)
- Merge tag '9.1.66' into develop [`6b9969e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6b9969e3e0f50f4cc61a4189d7e48f8f895239a8)
#### [9.1.66](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.65...9.1.66)
> 6 November 2017
- Fixed issue with post-processing folders and files with unicode characters in their names [`4c2676f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4c2676fd62a2966b3dbe565e881fd7209d4f31b5)
- Release v9.1.66 [`735906d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/735906d36d2c560de285b38a85b6b79bed68d9d9)
- Fixed issue with post-processing folders and files with unicode characters in their names [`aa334f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aa334f6ce6f4fcc81bed78606951b1cbdacaaf58)
- Fix issue with checking for latest version via git [`9b68632`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9b68632c1cf38d65398c90c2a03a58375af7dfb8)
- Fixed issue with post-processing folders and files with unicode characters in their names [`8a5d431`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a5d43133aa5855a8f2f8e5575d2eabd0648b69e)
- Merge tag '9.1.65' into develop [`589eac2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/589eac2d5f0ce2fb8fe22c4a6b637b3bea624297)
#### [9.1.65](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.64...9.1.65)
> 6 November 2017
- Release v9.1.65 [`56217dd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/56217dd120e0e425bd27d0ae0c9b9b715222e5d3)
- Merge tag '9.1.64' into develop [`97fedde`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/97feddef20f932ce95a13a4144af04213422953c)
#### [9.1.64](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.63...9.1.64)
> 5 November 2017
- Release v9.1.64 [`a5cd4f5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a5cd4f5285c79385c820b1c7e7a399085add36b5)
- added code to Newpct torrent provider to search page by page [`fd03d0c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fd03d0cb8027dfa54b1f1204302308975296dacf)
- Fixed issues with Newpct provider searches [`08aadb2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08aadb21578fc5a3722015168905a5cc4f90f59d)
- Fixed regex's for Newpct provider and added search url for HD series [`1260ed4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1260ed44631d1bed3a52b1a0445fba87415f38ca)
- Fixed regex's for Newpct provider and added search url for HD series [`209d748`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/209d748b29448b69af78e4354be7b93d3a8b5a5a)
- Fixed encoding/decoding unicode issues with tuples and kludge [`68d647b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/68d647b441a6df5e9bab871a020ded27cb60e64d)
- Fixed encoding/decoding unicode issues with tuples and kludge [`394338f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/394338f4265914a3cdbeadf9a2824fa18ba713aa)
- Fixed regex's for Newpct provider and added search url for HD series [`31c2cbe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/31c2cbedc03b9ca6b9f1eccd94d19354634bd02b)
- fixed post-processor queue issues with none types [`02e5733`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/02e5733675bef5b30cf7d0bfe4fd8394e8f112c7)
- Fixed issues with Newpct provider searches [`e131756`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e13175646221fccb688408506d364d642139a760)
- fixed post-processor queue issues with none types [`373a99f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/373a99f657f5c4193e1d4e78701bc99038a7e7a7)
- Fixed quality regex for Newpct [`02baa59`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/02baa594ff420229799079c33a1e1a817847eb7d)
- Fixed quality regex for Newpct [`ccc4dd6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ccc4dd612c98045d7f203f1796c01f1c1f40da39)
- fixed post-processor queue issues with none types [`0c46c22`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0c46c22463daa604e81c3f77177ed4bc21730cb2)
- Merge tag '9.1.63' into develop [`d64aa8e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d64aa8efe78c29e5c7083955f95e080dea1f0206)
#### [9.1.63](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.62...9.1.63)
> 4 November 2017
- Release v9.1.63 [`b0b02e3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0b02e3ec514b917ca337da416af09a809895867)
- refactored more torrent providers [`6820bf0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6820bf0759355ac419c10f9e741ce563b52dd36b)
- Refactoring search providers [`ebb2a6b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ebb2a6be83cac783f26b1860814dfbe713bf8e0d)
- Refactoring search providers [`4d52518`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d5251888f94fd711ecf40c82c983f3edcac6ce9)
- Refactored search providers [`ed3f92d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ed3f92dd07bbfcd1c2f0aacaaa226408c4ef4b45)
- Refactored provider proper searches [`ac96d4d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ac96d4d9b81f904c83eaf73161c484e7adaa2bb5)
- refactored minimum seeders and leechers checks [`90308f0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90308f02bb0dd1f8e3e41cfe9ab080f85e057c72)
- refactored torrent providers [`0bf0945`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0bf09452ff481a3e32058c17bd85b0e0b7c09754)
- Fixed issue #102 - Newpct.com changed his web structure [`5cea4c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5cea4c490ab7112fd63c432c35a53f77d204a318)
- refactored newpct provider [`00b3ffb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/00b3ffb85e347cd248180138f0330912ffdfec68)
- added download client setting for torrent clients to convert torrent file links to magnetic links, helps resolve download issues for certain clients and only works with public torrent providers [`0e2ebef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0e2ebefd3e92e698fffecd3152ad61d18cd894fd)
- Updated grunt file to reflect repo changes [`7f450e6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f450e6828e0cf8e03394d1855d33925175b459c)
- Merge tag '9.1.62' into develop [`e7f8371`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e7f8371224bc024ef745b236893856243617e3fd)
#### [9.1.62](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.60...9.1.62)
> 29 October 2017
- Enabled caching for all providers [`7b6bbe3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b6bbe3f1733b0d0de13825379b157e0c80cb0d8)
- Release v9.1.62 [`c174e09`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c174e098c7e250886072ba80d78212ddaf4af7b8)
- Fixed default poster size [`a90e20b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a90e20bf36bae9b1ea866be3ea309a26fd58eb48)
- Merge tag '9.1.60' into develop [`e6cbf1d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e6cbf1d411448e64352973295d4eff21f44e9ddd)
#### [9.1.60](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.59...9.1.60)
> 28 October 2017
- Release v9.1.60 [`ad2f5d9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ad2f5d9ad33c96553b61cfc7b3af91941f4d3d05)
- Merge tag '9.1.59' into develop [`2070b4d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2070b4d49b0f5febb2c4cd3d1eb70d882e1539e6)
#### [9.1.59](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.58...9.1.59)
> 28 October 2017
- Release v9.1.59 [`b30936a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b30936ab667449318c490a4a7f8c99e5402271a7)
- cleanup code [`4c26bb0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4c26bb0f2cb05279dbb412579c39928cee607711)
- Fixed issue with verifying search results [`56a04dc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/56a04dcbe8062b1a354057e77b6a3721620ae94a)
- Merge tag '9.1.58' into develop [`08eea41`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08eea41736fed82e978b6c6f514712e1a5eabfec)
#### [9.1.58](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.57...9.1.58)
> 27 October 2017
- Release v9.1.58 [`78f6aff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/78f6affcd9fadd8d8de6ebec0ed61e61e09dbd19)
- added code to verify all provider search results content when picking best result [`074910e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/074910e59b186d5fc1240499e77e072f3fad0743)
- public torrent trackers now added to both magnet and content if exists [`5d29937`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5d299379561a6d2501ef15b5da7b7e11b748cd44)
- Fixed issues with starting app under service in daemon mode as unprivileged user [`1f182f0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f182f0cd63dd62544e0e1eaed988742b671b207)
- Merge tag '9.1.57' into develop [`749caeb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/749caeb69b16181328193c877181ad7c6e8e718c)
#### [9.1.57](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.56...9.1.57)
> 27 October 2017
- Release v9.1.57 [`492a3fb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/492a3fba9b1fe7eaa73753f92345781f40876e0b)
- Merge tag '9.1.56' into develop [`5371cb0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5371cb02078d27729f3b16c62394083270b487ed)
#### [9.1.56](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.55...9.1.56)
> 27 October 2017
- Release v9.1.56 [`1d4bc73`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1d4bc73fcfff52da3e5f6b40583898cd33eed5e4)
- added feature to automatically add verified public torrent trackers to both torrent files and torrent magnet links for public torrent providers to help improve download reliability and speed [`6382b2e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6382b2ed446333abf7d7e7d02c0c158baca8daa9)
- Updated docstring [`2ca0866`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2ca086670df8f109d9761e2e732a84e345b52f2f)
- Fixed url for torrent public tracker list [`ef53a1d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ef53a1d460d14cbfe5d6d307f22bb1ff95f5c865)
- Merge tag '9.1.55' into develop [`675d287`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/675d2877a34935285efc96e99fa61139a3e69410)
#### [9.1.55](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.54...9.1.55)
> 26 October 2017
- Release v9.1.55 [`8a121c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a121c76537a47511a6aabc1f0a0045ddd91686b)
- Fixed issue #91 - object of type 'long' has no len() for newznab providers [`043f827`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/043f82707ca5a44529f2e0f78bd9bbe8da11febb)
- Merge tag '9.1.54' into develop [`48ad850`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/48ad8507d1e0a236d7e3f34301e2cbeeb591bc30)
#### [9.1.54](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.53...9.1.54)
> 26 October 2017
- Fixed issues with clearing out stale *.pyc files [`5a73364`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5a73364c3676fef00faa1ca9fd9693991d6bfc11)
- Release v9.1.54 [`a3c8725`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a3c87254fa048573d294c9b5f9a3202b5833621a)
- Merge tag '9.1.53' into develop [`0787004`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/07870045760b37fd7c6a447819105ba38b72f47d)
#### [9.1.53](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.52...9.1.53)
> 25 October 2017
- Release v9.1.53 [`57bf43e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/57bf43edab67dd95e0946b3765eb1b1d0f1cd2b4)
- Fixed issue with wanted and missing labeling [`f90baa4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f90baa4a6b321d571b03e35ce8fc23606107465d)
- Merge tag '9.1.52' into develop [`d4650b8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d4650b8b95770c54ca7287235ad54930e075a384)
#### [9.1.52](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.51...9.1.52)
> 24 October 2017
- Release v9.1.52 [`c5143b6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c5143b6a35503d5e086dc282422ebc16d5ee2fb3)
- Fixed setup import errors for babel [`dfdaf49`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dfdaf498aae57dd05a8f8803aafe880c78ae2410)
- Refactoring requirements.txt [`c7de2b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c7de2b363f07ce51576183dec7116338423f1b05)
- Refactoring requirements.txt [`036fc03`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/036fc0308893391103b0e8eedd13b208be56753f)
- Updated url to favicon for notifications [`68ee394`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/68ee3943a3d8af6f78fff67e6e62449c6d9bad62)
- Refactoring requirements.txt [`2a15a42`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2a15a42dd59923a93893236d832fd9ab64af9f5c)
- Updated url to favicon for notifications [`7772474`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7772474b03af4b1fb36f4e30fc328183ad6d7e8f)
- updated readme logo [`0b218f2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0b218f261e12d62beeb19be45038cdf1eede1d0e)
- Refactoring requirements.txt [`3df51c0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3df51c00882c9abcee44fef1dd6af6985f7f81c8)
- Merge tag '9.1.51' into develop [`1d4aae5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1d4aae5c331d0e2f24451229434e6d67a2d38a2e)
#### [9.1.51](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.50...9.1.51)
> 24 October 2017
- Release v9.1.51 [`9ca9dc4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9ca9dc4711ca85f0eeecdaaf9223536ee29b1620)
- Merge tag '9.1.50' into develop [`e98292c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e98292c4fe895da3f8d69f61646ec2e6dbd2c969)
#### [9.1.50](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.49...9.1.50)
> 24 October 2017
- Release v9.1.50 [`e94d370`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e94d370832df7180b315e300a4d6194240d70a4b)
- Changed urls for network timezones and scene exceptions to use our new CDN server address [`151fb91`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/151fb91124f7ffcea4cd0a67db176948469592cd)
- Changed urls for network timezones and scene exceptions to use our new CDN server address [`563f61f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/563f61ff3db1b2adaa2b3132163ad875b295ab86)
- Merge tag '9.1.49' into develop [`cc1f651`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cc1f6513064823cb1a9b94a7c97d42f69875f7ae)
#### [9.1.49](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.48...9.1.49)
> 23 October 2017
- Release v9.1.49 [`2ae8886`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2ae88860228f8cf5e3b99ec7066a14228e7db763)
- Refactored logo [`9419272`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/94192728a0f9842ce0362d6662c2ce1fea4fb24e)
- Merge tag '9.1.48' into develop [`2e3ffba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2e3ffba75f02a0621add675a947d3c5c2b64ea33)
#### [9.1.48](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.47...9.1.48)
> 23 October 2017
- Release v9.1.48 [`b51b312`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b51b3121b0edcda4e1f0b133b992805317009e8c)
- Refactored code [`32e2fd7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/32e2fd7f905cc040afec62c40adfcfde34af0b57)
- Refactored logo [`8c12317`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8c12317aead42af053085b77b1741587973b8c55)
- Updated .gitignore file [`ec907f7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ec907f7430f0abba8e7959cc2654b4bc20283300)
- Update Bug.md [`08384bf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08384bfc3eab8e5eb04aee5abfff6c82525094b2)
- Update Bug.md [`b29dc99`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b29dc992963493aeb5292dc670389c9a8fe9ef0b)
- Renamed template and fixed small markdown typo [`801c6a3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/801c6a326b2e0e84af2d3fab4b87e94c4c286b39)
- Merge tag '9.1.47' into develop [`19c8fc9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/19c8fc9bc36ec11ece946fb4d0a50d7db3c7ba65)
#### [9.1.47](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.46...9.1.47)
> 21 October 2017
- Release v9.1.47 [`e799d93`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e799d937a2219784f4814a6003c4e23fcd1af6fe)
- Fixed UnicodeDecodeError for retrieving messages.json data [`07fe860`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/07fe8603fd4d28d0c862573df4c6b5461726148f)
- Merge tag '9.1.46' into develop [`26f9cf3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/26f9cf3821845fa9878474d2b7392e217ca999d1)
#### [9.1.46](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.45...9.1.46)
> 19 October 2017
- Release v9.1.46 [`c470b37`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c470b376e396f3a5810fd7d9c207e8d816dd0349)
- Fixed issue #94 - manual post processing error [`b896e96`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b896e9694b8f12360cf040ce1f51cfc11957d6fc)
- Merge tag '9.1.45' into develop [`3182cdc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3182cdc2e6320240e88556d719f845d51c1b3c5d)
#### [9.1.45](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.44...9.1.45)
> 18 October 2017
- Release v9.1.45 [`b0b9201`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0b920167ed2602cb3f48ac5c0aac8cf7b824c09)
- Refactored qBittorent [`44b2225`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/44b22256062a54377cc7309890ff6792dd991753)
- Fixed source url for login page logo [`71563bd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/71563bd3fa99fd97cc2a3e8656a1040620ee0c23)
- Fixed source url for login page logo [`d41ddae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d41ddaef98ae7f54cbd48dc3b2c50dc9baf0574c)
- Merge tag '9.1.44' into develop [`7ddfa59`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7ddfa59fd085e53ac4506e5665f4a4b62774f858)
#### [9.1.44](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.43...9.1.44)
> 17 October 2017
- Release v9.1.44 [`59f9fbc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/59f9fbcbe6a8ab54f5bea6f0403db2c8bb072c69)
- Fixed issue with log_dir attrib missing [`08fdbad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08fdbad2b27b4aa1438a1940d832445993510023)
- Merge tag '9.1.43' into develop [`70b4e32`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/70b4e32172476c1a176009c3ff1d047eea133647)
#### [9.1.43](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.42...9.1.43)
> 17 October 2017
- Release v9.1.43 [`25f71bf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/25f71bfbc74e39c4c582eb42dfda7f8e2487e763)
- Merge tag '9.1.42' into develop [`6fb9cd9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6fb9cd9cb33971f9a1e803a72bb414cb58c03d00)
#### [9.1.42](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.40...9.1.42)
> 17 October 2017
- Release v9.1.42 [`f915a35`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f915a35bc723dc20fce39778d496ae1719ae5067)
- Fixed attribute error for postprocessing queue [`5563b94`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5563b946429ca1b94d977cd0c261afbfd3f04e1f)
- Merge tag '9.1.40' into develop [`5f92917`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5f9291773ffbfa6e4fcf5a6c923ae842eaa65518)
#### [9.1.40](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.39...9.1.40)
> 17 October 2017
- Release v9.1.40 [`fea50e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fea50e214de3e228dab4cd043f309125bae742bc)
- Refactored Newznab provider code [`f45988b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f45988baf594f32258a50c814cdc563ebe73c22e)
- Refactored Newznab provider code [`7aac26b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7aac26b4491f8edbd9275c1f9aceaa8e1555e0fc)
- Merge tag '9.1.39' into develop [`871fdb7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/871fdb71e8f4432bd140d9fad9eb26b5d1ba604f)
#### [9.1.39](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.38...9.1.39)
> 17 October 2017
- Fixed issue #90 - iptorrents provider needs update [`1da0430`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1da0430d743ff333fef9cdb9d318f20fdd07b9a5)
- Fixed issue with gettext underscore being replaced when using underscore as throwaway variable [`f50a313`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f50a313c8322679fdea2b30c420d182b92398e02)
- Release v9.1.39 [`6384aab`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6384aabf545605f030f4ce04377b6116d396d70a)
- Merge tag '9.1.38' into develop [`0545329`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/05453299fd2ee292a1db80fe16ec212256506ca0)
#### [9.1.38](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.36...9.1.38)
> 16 October 2017
- Converted more templates to i18n [`2abfe11`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2abfe11c73ee3073646fe131256134cc7273de26)
- Finish i18n feature code [`51e2aae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/51e2aaec77c76bd2fa46423cab610805f96a426d)
- Fixed 'No Content' error and added more translated languages [`372b24e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/372b24efd5444a98b016eb1358dfb5b8a4ae03d2)
- Extracted more gettext messages [`939e18f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/939e18f603603b2d0a1e498b82b994c8cc1add46)
- Fixed issues with json gettext [`a3fd581`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a3fd581b4c7a125a9b94f251cfb0e953092e6cef)
- Fixed issues with setting minimum seeders and leechers [`c1ab882`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c1ab882ef0485ac07f9dfbf6a66444bcca207d40)
- Converted more strings to i18n [`76cca85`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/76cca8516a6c795e24f627f538b6814387359842)
- Converted headers and titles to i18n [`104ae0a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/104ae0afd46e6192882ca95af62b137d76f72f4e)
- Optimized placement of gettext installation code [`7b9275f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b9275f01a45aa193383d73fff087b242a638e80)
- Clears current user on restarts to disable header and footers and force re-login [`7927b8c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7927b8cebe2c98908ce1f192e74e9f3a6c95a33a)
- Release v9.1.38 [`8a3d08a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a3d08a0dcd3e34f0d0be512bc35db3e9b70a283)
- Disabled header for restart page [`4f214c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4f214c46c068c126b8206137e77e401e011c19e7)
- Fixed typo in main template [`892d3ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/892d3ce5b453db9fed9b24f0a9438d413144225b)
- Clears current user on restarts to disable header and footers and force re-login [`d8302b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d8302b2c678279f39ecb07c366af6c98bc9c2961)
- Merge tag '9.1.36' into develop [`0b93540`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0b935402ea86efa9475b0c36dcb8f78d4ca968fa)
#### [9.1.36](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.35...9.1.36)
> 13 October 2017
- Cleaned up more of the provider module code [`c0bdad9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c0bdad99de81c727fae3bd3b222295c768fa4f5b)
- Cleanup of all provider module code [`a748503`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a748503eb3ce88350697942baf34a6b2c4961eaa)
- Misc code cleanup [`47dc9a4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/47dc9a432c2bef7b9eaced114df3b3be87441c75)
- Fixed small issue with HDBits [`a4c60fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4c60feaefa2d852cfe71580484548b3b458e213)
- Fixed some typo's [`e127e2a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e127e2a11e2edb6a2c874edfcdb87d4bb7a7eae0)
- Release v9.1.36 [`7d2ff8a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7d2ff8ad476e2aaad55c85b2b3d3484012d5dafd)
- Merge tag '9.1.35' into develop [`242acae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/242acaed544df9303360c2935dd6cd86fa7dd72e)
#### [9.1.35](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.34...9.1.35)
> 11 October 2017
- Release v9.1.35 [`a868e4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a868e4b1adff33654b958e0253627dc251293af7)
- Merge tag '9.1.34' into develop [`4bad6a7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4bad6a758d89231c4c1610c99156b0d5df6a3ad3)
#### [9.1.34](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.33...9.1.34)
> 11 October 2017
- Cleaned up provider code, removed providers that where no longer working [`c2e364f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c2e364fe01372434d4e96bc908988892200cefba)
- Configs are now loaded and saved using system encoding to resolve unicode issues [`061f090`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/061f09040e931f50b2e2b25de12e5d06d67b58b7)
- Release v9.1.34 [`27f5848`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/27f5848deb3b070ebdd64b493ccd7fbb70269f20)
- Merge tag '9.1.33' into develop [`9c0fd6a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9c0fd6af17c9cbbb0575d08fa834ac42b0816af1)
#### [9.1.33](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.32...9.1.33)
> 10 October 2017
- Merged manage searches webui template into manage queues template [`54238a1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/54238a1996ff541ef0a1ff157cefb88b27b80e66)
- Fixed issues with restoring older backup files that may contain sickbeard.db file [`d9cfc11`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d9cfc11e15d97d77e7c2078b0dcb45ee3ab7163b)
- Release v9.1.33 [`819d4dc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/819d4dc813b8901b79b021bbbb067d22f22a28b6)
- Merge tag '9.1.32' into develop [`00d5ef7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/00d5ef7c20401634bffda0aa0efebdf3cd50d0d7)
#### [9.1.32](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.31...9.1.32)
> 9 October 2017
- Release v9.1.32 [`f372ab4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f372ab459a347e26505604ba93fd5fb6cb113098)
- Merge tag '9.1.31' into develop [`a086865`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a086865958f16f7c30beb35938f4138511ced0d1)
#### [9.1.31](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.30...9.1.31)
> 7 October 2017
- Release v9.1.31 [`12b6e6b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/12b6e6bc7e2669e9aaf43b700fbb01cfa5cb7f20)
- Merge tag '9.1.30' into develop [`f34d160`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f34d1605ff79566f9328df75b2e87cabe3ef7fe5)
#### [9.1.30](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.29...9.1.30)
> 7 October 2017
- Updated general advanced settings to allow setting of PIP path [`b8786d6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8786d6fc18433223dc429a40501b14c0457b0ee)
- Release v9.1.30 [`cd9041d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cd9041dd75cbd87a114a7875bd9d0e79c7dc4469)
- Merge tag '9.1.29' into develop [`55eb7f7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/55eb7f7aa6dc6f292bf62260e699b4b46eeb2794)
#### [9.1.29](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.28...9.1.29)
> 7 October 2017
- Updated requirements [`8562a7d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8562a7d9d0a99322fe85cda9d1330dfc003c8b5c)
- Release v9.1.29 [`1b67369`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1b67369966e056a0c8f5b6c80907bc21b44e3839)
- Merge tag '9.1.28' into develop [`1d56992`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1d569920cb937fdc30c2c0ada64380101ea76820)
#### [9.1.28](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.27...9.1.28)
> 6 October 2017
- Release v9.1.28 [`d06862a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d06862aec0d52e1fea0d9cdca9db03cee7584058)
- Merge tag '9.1.27' into develop [`b04d8fb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b04d8fb042cd86b15508167dbbd1440bced68b36)
#### [9.1.27](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.26...9.1.27)
> 4 October 2017
- Removed async for login handler [`c4277b5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c4277b5177f86cbe8bd9fbc4f995c5e15af4edc7)
- Release v9.1.27 [`3732ce2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3732ce2428667fb4496491db435d592205d40ebf)
- Removed async for login handler [`4a81426`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4a814260f71aa97bb14ff01708217a550bd3bcd1)
- Merge tag '9.1.26' into develop [`3b7e618`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3b7e618c280bf50e9d9d22dca9d88f2125f9175c)
#### [9.1.26](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.25...9.1.26)
> 4 October 2017
- Release v9.1.26 [`4070c4c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4070c4ce5ae64da1510e95861e498afb4864b3f2)
- Fixed issues with saving settings [`156c0f3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/156c0f312b30446190c82af28b2f936cfdb52b9d)
- Merge tag '9.1.25' into develop [`f040ea3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f040ea3f93dca4cfcb29df1db92f401d6ac4e0e1)
#### [9.1.25](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.24...9.1.25)
> 3 October 2017
- Improved censorship of sensitive data in logs [`e1c6cdc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e1c6cdc50522f95da75391f833642d0fd22ebd8d)
- Release v9.1.25 [`3ec56ef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3ec56ef046bea47cbdb38070bbd964425c047ec5)
- Merge tag '9.1.24' into develop [`25e6f80`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/25e6f80bf11ffa3c545edcf1eaa1d2fa69d3d94b)
#### [9.1.24](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.23...9.1.24)
> 1 October 2017
- Metadata for actors is now pulled from indexers using a function [`8c581c5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8c581c5aa57434a6de18c048c468f3dcd8523932)
- Release v9.1.24 [`077a85c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/077a85c5e8eb97677ba515de3ca20ea9c409c00c)
- Merge tag '9.1.23' into develop [`dd7415e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dd7415eb783c00e9971148f9c74ee601b83d51b1)
#### [9.1.23](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.20...9.1.23)
> 30 September 2017
- Fixed issues with login function for webui [`7c63227`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7c632274d72174d5a2dd244cb8d17ecf84f3f63d)
- Release v9.1.23 [`a99f625`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a99f625f2c84baeb558365c351ef68d851f4a709)
- Fixed issues with login handler [`0bb6c69`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0bb6c69f8d4730deba704df4da06c58172f8896c)
- Removed code that manually sorted trakt shows by votes before display on page [`85812da`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/85812da783e0fa4e4a3a73fe3ba70e922366c98d)
- Checks current user before attempting to auth for login [`257d1f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/257d1f90c9ae5f8ccbe9d95b26a8de48d82615ec)
- Fixed typo [`4295e55`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4295e5535d0b1ae2afa83dff2439d1add4fc8bec)
- Merge tag '9.1.20' into develop [`dd84f3d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dd84f3d9544562137329f48d4d4dadec9d152b04)
#### [9.1.20](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.19...9.1.20)
> 29 September 2017
- Release v9.1.20 [`cd6f0fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cd6f0fe603d1d7ebd146f46983863dfc8976666f)
- Merge tag '9.1.19' into develop [`c3eb23a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c3eb23affabcc12a84474582d63c89d1f9914b46)
#### [9.1.19](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.18...9.1.19)
> 29 September 2017
- Fixed duplicate issue with configure provider select box [`b8adf84`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8adf846451989d69eced4291fc164704b8837bd)
- Release v9.1.19 [`f0c8cbe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f0c8cbefc84c78db119d962e7e4b323322c3fd8e)
- Merge tag '9.1.18' into develop [`31830ff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/31830ffa2600df9a18b63aad6a90741bc751678c)
#### [9.1.18](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.17...9.1.18)
> 18 September 2017
- Fix for issue #71 - removes format metadata from video file [`1e5bd13`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1e5bd13558db30556d5ecad4a55c3097c4bae208)
- Release v9.1.18 [`4b1e431`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4b1e431d56867da0c1b0d04a2c0d3855389573c2)
- Fixed issue with retrieving cached results for searches when performing a provider search [`a6a84d4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a6a84d4f65c31525062429515db22344fe4ee44c)
- Merge tag '9.1.17' into develop [`138478d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/138478d07ebf19edfc5c385a27e4f803cbb99846)
#### [9.1.17](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.16...9.1.17)
> 10 September 2017
- Release v9.1.17 [`489ea29`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/489ea29d4815bfe968502a2158497d0d4b180b31)
- Fixed issue #77 - strips whitespaces if show airs property is blank [`d3cf02c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d3cf02cf6f880ff1edae90da58cf4123ec066ed6)
- Merge tag '9.1.16' into develop [`a4dbe5f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4dbe5fc74bcdf3ff930e76b8024966f05c38ee2)
#### [9.1.16](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.15...9.1.16)
> 5 September 2017
- Cleanup of subtitle mako templates [`fe775d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fe775d7c25222a7abb50790dc8b10877dd3cd1b4)
- Fixed issues with scene numbering functions [`bb4adb8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bb4adb836ef1c8dd8f5d989e82f531af4a611ce6)
- Removed next episode scheduler [`18bf4b5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/18bf4b5072bb3320c91bf18cbf4e78158caa459f)
- Fixed issue #71 - missed subtitles search [`e10fec6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e10fec636ba615b1645b7b74b62d1d4e9ac2f551)
- Changed minimum allowed python version to 2.7.8 [`0a0ff73`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a0ff7330d8dc49f6e1068635168b2a3de241798)
- Removed shutting down scheduler, may be causing restarts to lock up [`2b006c0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2b006c04caa82aaa49a6a9e61e08e68e2b90feb5)
- Release v9.1.16 [`1a64092`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1a64092428dde8fdc2106ca2191ab309fa8388ca)
- Merge tag '9.1.15' into develop [`3cc59c1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3cc59c113201b21d545579c161c0d5cc488e91a9)
#### [9.1.15](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.14...9.1.15)
> 30 August 2017
- Fixed failed download handling [`ff9dbcb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ff9dbcb48aad90636f36c329faf5f7054eb5ad22)
- Fixed EOF issue related to pickled settings with new configs [`f9f02ff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f9f02ff41ea4a489954504625e4a450d3082f0d9)
- Release v9.1.15 [`39ca900`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/39ca900647edaf4d80a77affcae509653b2db603)
- Merge tag '9.1.14' into develop [`59f8199`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/59f8199aeab7371fa586562ee5cc34c6e4e4114b)
#### [9.1.14](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.13...9.1.14)
> 28 August 2017
- Using pickle instead of json for storing config settings when needed, retains integers for dict keys. [`d9b6217`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d9b62176f517219bc312cb2d1baed68c5dfd9ba7)
- Corrected trakt data generator code [`9d2b9de`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9d2b9de7ae75397335d067b1941dd94d892b2d22)
- Convert results back from indexers into integers before comparison. [`900c785`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/900c7858471581bcc5702f4ca7bf84d115f57db8)
- Release v9.1.14 [`1e1a90b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1e1a90b432add08d905581fd0e98a3a2184f55c1)
- Updated network logos [`be50e92`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/be50e924fbc4b33b710d22e99f420e2692d75631)
- Merge tag '9.1.13' into develop [`d309e8b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d309e8be05fcd1b54429b24a4dd8fca48bfddf03)
#### [9.1.13](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.10...9.1.13)
> 27 August 2017
- Fixed startup issue do to unicode decode on os.walk [`b6172d5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b6172d587d185167326a7698c740b8848abe980c)
- Moved code to core for removing stale .pyc files [`27326ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/27326cade41c435d731c30b90d4a46072880c876)
- Release v9.1.13 [`81ac249`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/81ac249f732a150500458566f5451d85eebece7d)
- Fixed fanart lib issues [`dcfdc7f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dcfdc7f87719116f07331a79348680190ca19e09)
- Removed LXML warning as we've replaced that with html5lib [`b2b3a7b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b2b3a7bd7ee8ba73d2ba579907e587ef40012096)
- Fixed shutdown issues with queues [`eba1be4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eba1be42600519e694828cfb90acac53f722e05b)
- Merge tag '9.1.10' into develop [`d98d592`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d98d5921e9f88057fff6475113d670237444677e)
#### [9.1.10](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.9...9.1.10)
> 22 August 2017
- Fixed app restart issues [`b5ad47a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b5ad47a40bd08137eb664e1602e38fc9f8b7f16b)
- Release v9.1.10 [`1662bb7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1662bb7275009159c9924a541bd2ce00d1a61cfe)
- Merge tag '9.1.9' into develop [`f793d98`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f793d98a5f12352090a3e97e46732fd303e35c21)
#### [9.1.9](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.8...9.1.9)
> 22 August 2017
- Removed shutting down scheduler [`36c64f2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/36c64f28f5ba5d01b0a8d207a745c7f0ce47e486)
- Release v9.1.9 [`ba560dc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ba560dc27bed35631cf539b30174c94d491f174f)
- Merge tag '9.1.8' into develop [`087dd9f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/087dd9f26e9c5c9fca2d8efe6543d71de1bc8681)
#### [9.1.8](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.7...9.1.8)
> 21 August 2017
- Release v9.1.8 [`730db3d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/730db3d3fcd84ea4083fe08be48fc6f37ae1be25)
- Downgraded cfscrape to v1.7.1 [`ad759ad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ad759adeeca6f0fa19db9f2fdee5bbb5600db616)
- Merge tag '9.1.7' into develop [`171dcf4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/171dcf4f9127a682ee5c7c2968ead8f2aa79b8a2)
#### [9.1.7](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.6...9.1.7)
> 21 August 2017
- Release v9.1.7 [`a3012f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a3012f955537198cd0eef65a56b4ffd74cc06937)
- Merge tag '9.1.6' into develop [`b282bdd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b282bdd27d3b707239dfb78a603b6be3bcd227d1)
#### [9.1.6](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.5...9.1.6)
> 20 August 2017
- Manual re-scan of files will force populate show images and overwrite existing image files [`22a13d3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22a13d3c57d0a3d339129f94168d700a6a7dd23f)
- Downloading from torrent cache urls is now retried twice to make sure its a invalid download [`f518e6a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f518e6a02f664e0c6130945d571d85aac90bb68c)
- Removed allow_redirects [`12fd7b5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/12fd7b5ba2a35d14da5f771b02a4ddd6dda78aac)
- Release v9.1.6 [`2cf9098`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2cf9098ab6dddd53e0e9ac2d7db2fb44027d5215)
- Disabled verifying ssl certs and cache for downloading torrent files from torrent cache sites [`385b6f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/385b6f105cee0bcc57ef055284709e4e4fc7a87e)
- Merge tag '9.1.5' into develop [`8415597`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/84155976be67d1b026da87510dd133509427de3c)
#### [9.1.5](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.4...9.1.5)
> 17 August 2017
- Release v9.1.5 [`13231a1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/13231a19588974247ed2f17fa20f8e173b6e2026)
- Merge tag '9.1.4' into develop [`107e2c6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/107e2c6818b846e945c8d7dc921711f3e42c81c0)
#### [9.1.4](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.3...9.1.4)
> 17 August 2017
- Misc template code cleanup [`eca5647`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eca564775e8de34cba39cab4e42d99ddef706a0c)
- Release v9.1.4 [`c055429`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c055429519ee343e93273206d6a654755674ae30)
- Fixed issues with adding a new show [`306d6b0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/306d6b03cfa5d536b4a3fe187d867754027152ad)
- Merge tag '9.1.3' into develop [`64b0779`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/64b07790cdecc947697b2ba625245f4fe3dbe31d)
#### [9.1.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.1.1...9.1.3)
> 15 August 2017
- Cleaned up bower installs [`a162a88`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a162a885a9e618f1c6456179f292b9942c687ed1)
- Release v9.1.3 [`4794c94`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4794c94bddbfae366cd0aa1cd9077cae83d6736e)
- Merge tag '9.1.1' into develop [`f077c2c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f077c2cca473d658bf475f26ecd7a9fc93fea587)
#### [9.1.1](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.90...9.1.1)
> 15 August 2017
- Fixed show/hide of content based on enabling a feature [`c071aec`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c071aec5a7645806130b6e8cd1dc5896ede55621)
- Updated logo [`6501a74`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6501a74ddf20a9e4fc97157fc1e8c6f280eb1e8a)
- Release v9.1.1 [`ea1a3e5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ea1a3e549df8974c2f850985469616cec235fa4b)
- Merge tag '9.0.90' into develop [`7928a75`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7928a754f69015291b5ac222f0e8e72225107a53)
#### [9.0.90](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.89...9.0.90)
> 14 August 2017
- Fixed tooltip issues and invalid number of columns issue with display show page [`399f86c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/399f86ca9b35e1c625336df3f0a3e08af3b02bdd)
- Fixed issue with display show title row [`fc35b2d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fc35b2d372ac6cdd28b7b69c3f5ed8ac7e4fb66a)
- Fixed tooltip issues for episode descriptions [`201c6eb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/201c6ebe55bba0ca63942d5a71e7c46013304545)
- Release v9.0.90 [`0178d4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0178d4b44bf4bba022353bb8685b5828118dcf70)
- Merge tag '9.0.89' into develop [`d78a55e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d78a55e9ba92abaec5c6794e126723d0372a153d)
#### [9.0.89](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.88...9.0.89)
> 13 August 2017
- Updated IMDB popular shows template [`34d0e15`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/34d0e15b1b4fbce0c76181fb988bd9d688a83a4f)
- Fixed issues with displaying show images on IMDB popular template [`c92a212`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c92a212ee9c2c5217beb15e0bb6ec15d9304f3df)
- Fixed change size function for popular shows [`aa835da`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aa835da69335fad7bf3045dd09d972a91d9f3da7)
- Release v9.0.89 [`12bbf4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/12bbf4b1fc3ec11f5e90e7ae6a20c4a861183209)
- Merge tag '9.0.88' into develop [`9ff2395`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9ff23952c986b6f9f7a4febd276fd928cef8ba4e)
#### [9.0.88](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.87...9.0.88)
> 13 August 2017
- Changed placement arrow icons [`8fcbf4a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8fcbf4ab0720ab827162de10631c827fe9acb40e)
- Fixes issue #47 - File air date stamping failed [`f0735a3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f0735a3b22093b85056fad1d7c1416fd8dcd145c)
- Updated non-release group names [`9389c56`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9389c5697aa3fa3f6f6fdb252a28e179ace96a4e)
- Updated main navbar icons [`6c71133`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6c7113392cb615497efbec7f87e0d74dea55ca7b)
- Fixed formatting of season and episode numbers to be 2 digits [`e355b98`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e355b98136b92428b73becff3e79c5cf078eebe8)
- Release v9.0.88 [`07d2ef9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/07d2ef90f9f421d277deeba7e323c8927fb5dc9f)
- Merge tag '9.0.87' into develop [`c1a1208`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c1a12085678077140ed19c92cf4d46e572d0f84b)
#### [9.0.87](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.85...9.0.87)
> 12 August 2017
- Release v9.0.87 [`4901a6e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4901a6e7648b955ce2604f78d70105eb21746272)
- Merge tag '9.0.85' into develop [`932302b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/932302bdc653e33b1a812801fbc26bbb0a720ce0)
#### [9.0.85](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.84...9.0.85)
> 12 August 2017
- Release v9.0.85 [`720826d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/720826d12cb6e5d012b4f936ba13200ff7cd4b65)
- Fixed typo in dailysearcher code [`baa2a29`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/baa2a29c1d47122d069f079e8ed34b384a7edabc)
- Merge tag '9.0.84' into develop [`c337cbb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c337cbb35e83af4ecbdad982baff30d8adc43832)
#### [9.0.84](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.83...9.0.84)
> 12 August 2017
- Misc code changes to startup and shutdown of app [`70902cd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/70902cda526c1c1c21576af0bb7d1245e100d057)
- Moved io loop to main thread [`32eabe0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/32eabe03169b2e5d4ff33176717d1a0cee1de421)
- Release v9.0.84 [`c803d2d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c803d2d839b1f0953a3573c164e7ec20355cd7b8)
- Merge tag '9.0.83' into develop [`6eff8cf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6eff8cf7f23bbb8863eed92bb6f15e57c00a7a36)
#### [9.0.83](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.82...9.0.83)
> 12 August 2017
- Updated regexes for nameparser [`1105065`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/11050656e34bef5978caf455fc63c5a6e099a6af)
- testing ioloop threaded [`cf2c0b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cf2c0b3165d376dfd2ca88283d5f1bb417869b6d)
- Revert "testing ioloop threaded" [`43ede21`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/43ede2116c2c0f4ae15d36d48f4eef6997310aa9)
- Misc fixes [`e7fdcba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e7fdcbaeba4fdd44cecc058f599cc81727ae78f0)
- Changed shutdown sequence [`6f7c227`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6f7c227b14ebd6225115d83320f741d33741b747)
- Fixed restarting issue [`736cbfc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/736cbfcc1d6e584d699ce09a8b6a1d1c8e7ed56c)
- Release v9.0.83 [`318669b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/318669bc0eacfee21a8448faf45e7b5f3edf8ef0)
- fixed typo [`e7cdb57`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e7cdb5767893a815ce6eb872a5e943ab8880fd54)
- Merge tag '9.0.82' into develop [`829ae1a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/829ae1a7a3612f3eea46169a68f8a6059a02376a)
#### [9.0.82](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.81...9.0.82)
> 11 August 2017
- Updated selectboxes in display show page template with class input350 [`b009b72`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b009b722a8fec82eecca8e723e8e76f62e58ec78)
- Release v9.0.82 [`6ffa4d0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6ffa4d0b8d8dc7baef49a1a0e0688b393e4835b4)
- Merge tag '9.0.81' into develop [`75be423`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/75be423b9d4ee2404758b9a39e834c66fa9852c1)
#### [9.0.81](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.78...9.0.81)
> 11 August 2017
- Fix #53 - unicode issue during post-processing [`#53`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/53)
- Removed size restrictions on selectboxes to make them more responsive. [`6ffa3ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6ffa3ba5524d9e1cd7c6f1ecda32818ad22d0af4)
- arguements passed from web views are now unicode encoded to resolve unicode decode issues within app [`b2b56f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b2b56f4f6db3f08ab115194b5b0fe0d088501aad)
- Release v9.0.81 [`4bc0209`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4bc0209d3e5fa991e4c1002d5a991f18d520edc6)
- Release v9.0.80 [`4a2fa3a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4a2fa3ad47c223b2d24830e0d886cb283865cc11)
- Merge tag '9.0.78' into develop [`4aacae4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4aacae4a3f2d4dc19f59b1314b68f0c549fec22a)
#### [9.0.78](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.77...9.0.78)
> 11 August 2017
- Changed layout for display show page and made it more responsive [`a888753`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a88875353ffab88e2ebe285aa40219f16b72ff58)
- Release v9.0.78 [`352fe0b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/352fe0bdd9a7d95116659f151ad84853e983d6f8)
- Merge tag '9.0.77' into develop [`c0f58db`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c0f58db070d1040cac1973df41b72f57e6301d7e)
#### [9.0.77](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.75...9.0.77)
> 11 August 2017
- Updated jquery-confirm bower package [`523b62a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/523b62a03e0ba214aaac3d04c2cd99c1db4960b9)
- Updated responsive code in templates [`35e0ad2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/35e0ad24b70cc8727cfd3114cd4a513b920e8be5)
- Fixed slow show adding to database issues [`677399e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/677399eb7d70e315e57243d04d753b3593913236)
- Cleaned up add show options and backlog templates [`9445b55`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9445b55610c8a7f1b51ab4595c2a7b3790e073fb)
- Fixed unicode decode issue [`f159260`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f15926053bd82de815e1f715d5d92ffeb5fa2536)
- Updated requirements [`ecabf80`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ecabf8037fe18aae69b877a90944eac829494a02)
- Release v9.0.77 [`15a7a0d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15a7a0d9a75cf85e1212e39b242617944340fe3d)
- Merge tag '9.0.75' into develop [`becb5ee`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/becb5eec09b542aa9125444472ba7d31324d7f40)
#### [9.0.75](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.74...9.0.75)
> 10 August 2017
- Notifications config template is now responsive [`93f109e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/93f109ec350f93c5045fdbdec08f9da5c6da6b84)
- Misc template cleanup [`668a726`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/668a72625107ba3a06032a612d319a619a4da02a)
- Providers config template is now responsive [`b681895`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b6818954b39a3cb04a38b73850f5e2b30ba3bf86)
- Updating post-processing template responsive code [`738d613`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/738d613268c3d83149520ac21822c0fcaaeb5497)
- Config -> General is now responsive [`3d2c071`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3d2c071bb4622e5a0997e5526fcd4b5a86fd57c6)
- Edit show template is now responsive [`d32f7e7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d32f7e794bf4631a96b7053c45a2ecaf82039dda)
- Core config code changes [`bdcebe1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bdcebe1cd4b73bd805f74f025ed0ac66e1a8c151)
- Post-processing config template is now responsive [`ea63857`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ea63857b9907929eddea8b6cf29de056550196a6)
- Misc template code cleanup [`bd9752f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bd9752f95886d25fe511b1036ff32ed51a04b9e0)
- Centered submenu buttons to top of page [`08a6479`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08a64795ee3bcbd4cd5a01fb2e5da9452137a677)
- Post-processing template is now responsive [`869ff4e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/869ff4e2b7d59e8da5031c3da183033b1ab96921)
- Backlog Overview template is now responsive [`7c23adc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7c23adc369db901b4f5a6c433265cf0c0b04280a)
- Misc responsive code cleanup [`c6b39cc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c6b39cc2c8971e19a586ab6e2bd9a20599db71db)
- Updated general config template to be responsive [`d0b1f6b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d0b1f6bf0f75bace0e244b230518fd0cfb23911c)
- Config info page is now responsive [`9db243e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9db243e81fa04e9bc7fd308f955f118abe955732)
- Manage searches template is now responisve [`1717a0a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1717a0a33ef58d497b197b23094fa8e4eed24ebe)
- Quality sizes config template is now responsive [`80bda17`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/80bda17eca1b865e11ee4217b49c548dbf994a85)
- Misc template tweaks [`92b7582`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/92b75822256515bbc454588c52d2a0ab805de80a)
- Misc template code cleanups [`d20f497`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d20f49758229f420cf0348cbb38a6f2cb16a347e)
- Misc code changes [`2409d7a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2409d7a1324c88684ff6be05c460b779d3ec0fc2)
- Misc changes [`ff3dca8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ff3dca8c8e78c4af469fd0ecd56c2a0e5db26db9)
- Web views are async now [`0f42df7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0f42df76c901826c8697e4c6fc0fc2e4f8578648)
- Misc code changes [`b7cbeba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b7cbebaf42e28aa6e7cfc90f54ad2ada3a7c791b)
- Web File Browser dialog box is now centered to screen correctly [`fabbf63`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fabbf63ea91af7bf08bb8df60d7baf066481bdf8)
- Fixed issue displaying show banner [`c41008e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c41008e61421f49e9a9b0415a040b8bf0532d009)
- Edit show template is now responsive [`0543be7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0543be731746eb6c1f70096fce6e974da25dbcc6)
- Release v9.0.75 [`9d2ba37`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9d2ba37ee2c3cc3a47839643035a0042f5e55c6b)
- Misc code changes [`e0d1e84`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0d1e84d0e7ac4668a830cf2e841e15632e051da)
- Misc code changes [`fdd5acd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fdd5acde6d0e1208d07f05af83cbef526da0430b)
- Misc code changes [`3a9ae65`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3a9ae6590a919041be5116be8894bb958e3251df)
- Misc code changes [`9078909`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9078909622d37a45b9fcedbb4e71125c8fd65841)
- Merge tag '9.0.74' into develop [`6dfeb92`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6dfeb92d86153164071cc5a5c08229fdb6400831)
#### [9.0.74](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.73...9.0.74)
> 9 August 2017
- Misc version updater code cleanup [`69b26f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/69b26f4bee2fc38b443f8b59240b1543ff3e796e)
- Fixed issue #47 - File air date stamping failed [`580ccdb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/580ccdbcf1e26e706431bed1ff041f2b1e91019d)
- #46 - Updated Nyatorrent provider url to nyaa.si [`194d14e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/194d14e16f9778af13207e9918ace64418a0b7d0)
- Release v9.0.74 [`25ba84f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/25ba84fd4f0879f9be02d58a43cb681f74f623ab)
- Merge tag '9.0.73' into develop [`9545030`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9545030dd9004c9b4ce0abf2db90f226c503b441)
#### [9.0.73](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.72...9.0.73)
> 8 August 2017
- Release v9.0.73 [`277d303`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/277d303965f0c6a4f6c4358d7086bf2a7e2e67b3)
- Merge tag '9.0.72' into develop [`262bb00`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/262bb00d707e089afe6cb31bdbf422cbebb6f70f)
#### [9.0.72](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.71...9.0.72)
> 8 August 2017
- Release v9.0.72 [`e679b10`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e679b106c4d70f211645328704a837fe54f4f886)
- Merge tag '9.0.71' into develop [`284aa43`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/284aa430514a421adaecdebcd947c807fe453531)
#### [9.0.71](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.70...9.0.71)
> 7 August 2017
- Fixed issues with retrieving show and episode images from indexer when show is not english [`c8dbc4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c8dbc4b7278bf8885fa16016a2f5d855981dfc14)
- Release v9.0.71 [`adb6543`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/adb654383cf3609290c6b85fbcf1c106c1e2ae95)
- Merge tag '9.0.70' into develop [`e0172c9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0172c9a55da8c93c00d10beb2f318cea72b73ec)
#### [9.0.70](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.69...9.0.70)
> 7 August 2017
- Release v9.0.70 [`062834a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/062834afbb4a60eb655c7463548a72a057b3abb3)
- Merge tag '9.0.69' into develop [`95ab385`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/95ab38577ed55446dddf920700de7e97a05f2568)
#### [9.0.69](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.68...9.0.69)
> 7 August 2017
- Release v9.0.69 [`24e488c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/24e488cc15ba401a677fbca768cb8f6103c007d3)
- Merge tag '9.0.68' into develop [`9d7801e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9d7801e00f32204400dc9e3ab5b95ef05cda696d)
#### [9.0.68](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.67...9.0.68)
> 6 August 2017
- Release v9.0.68 [`0cea9ef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0cea9ef49b1bdf06351ff887cb3e32fd18f45ae5)
- Merge tag '9.0.67' into develop [`5dd254e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5dd254e02eef67e57892ca9a5eb74d2f0e5a8fd9)
#### [9.0.67](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.66...9.0.67)
> 5 August 2017
- Fixed issue #20 - rar not working [`1d7b71a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1d7b71ab1cbabec7dd5ae292a80fc7041c4243e7)
- Release v9.0.67 [`6774207`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6774207b7a641a14028743885f665d3284854b40)
- Merge tag '9.0.66' into develop [`779a7c9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/779a7c947f2f95e3e2a97b62f4047d0e7f56e1e6)
#### [9.0.66](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.65...9.0.66)
> 5 August 2017
- Release v9.0.66 [`859f714`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/859f71487e2e5b8458a6f39c05cefedec9f165f0)
- Merge tag '9.0.65' into develop [`5e98653`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e986539deb34a9f5e08f03732467d3b9eff6852)
#### [9.0.65](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.63...9.0.65)
> 4 August 2017
- Release v9.0.65 [`0c55c51`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0c55c5172a34957029f4f6b537f959ea46b53498)
- Release v9.0.64 [`d96697c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d96697cd26478137af7faa208ad8fa5e7caea4dd)
- Merge tag '9.0.63' into develop [`c6c56e9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c6c56e95ac07f94d5a8c1833859e669d14ca9ec9)
#### [9.0.63](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.62...9.0.63)
> 4 August 2017
- Fixed issue #42 - Pushbullet Notifications Not Working [`6775391`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/677539109dd37bbf8e8bff551ed9c551fcb424cf)
- Release v9.0.63 [`a1277cf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a1277cfe9bf82a9ddf3817a22d6b68ba1f8264ab)
- Merge tag '9.0.62' into develop [`92af9e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/92af9e4cd480edf597cee752f41a5a892614ac58)
#### [9.0.62](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.61...9.0.62)
> 4 August 2017
- Release v9.0.62 [`15f720a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15f720a19fea206c6ac67633ea23ec0c739e496a)
- Merge tag '9.0.61' into develop [`a137310`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a1373100f973e394ffbfc5a7bfa93b6a61ba9ee5)
#### [9.0.61](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.44...9.0.61)
> 4 August 2017
- grunt tasks [`1735eaf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1735eafea29fc5fa2f80d4c4bfb2a51f8350b9e4)
- Release v9.0.60 [`5e8e772`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e8e7722a439322f581f9e6114086c4bcc7f6af6)
- Release v9.0.61 [`4effd2c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4effd2cb6eac5739e5fff4403fc9bf0ebdf34084)
- Merge tag '9.0.44' into develop [`8daaa26`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8daaa2680794adb1bd93fa9475cb4173a5f32fbc)
#### [9.0.44](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.43...9.0.44)
> 4 August 2017
- Fixed issue #33 with adding existing shows not detecting status of episode files on disk [`a3316de`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a3316dee3738ac3aa35e72f2663dcf368800fa48)
- Fixed issue with retrieving metadata for existing shows when adding them [`9d3fd0e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9d3fd0ed165425a8af674acb6b91325a3d0b65ab)
- Merge tag '9.0.43' into develop [`1c4ed45`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c4ed4565288cbc06423a5fecafa64141b71abe7)
#### [9.0.43](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.42...9.0.43)
> 3 August 2017
- set indexer searching for indexer ID is optional in nameparser [`f5ba588`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f5ba588e1910e6d534f20da844cef0e148e53402)
- Removed IMDB caching, not thread safe [`8d7f2e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8d7f2e22786256abb4d4582fa44958e412674667)
- Removed IMDB caching, not thread safe [`a43028f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a43028f1e1504884355b9f8b33a2f278bc67d2b5)
- Merge tag '9.0.42' into develop [`32ecd10`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/32ecd10be53be4acf708f1892f598e8debbe7235)
#### [9.0.42](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.41...9.0.42)
> 3 August 2017
- Removed toggle switches from mako pages [`bec0c7c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bec0c7c268b69c9c457d29f4a9bdd079ca714c3a)
- fonts and images now use directory refs instead of url refs, resolves issues when using web_root option [`0c50d02`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0c50d022045e58fba767ab1c5ada69ef957c3571)
- Fix for issue #39 [`39b65eb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/39b65eb391551abfbd94f8cb210d95cd8f8d7e2d)
- Merge tag '9.0.41' into develop [`2f79837`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f798371933ae6edf29086d77c9627cc250f42af)
#### [9.0.41](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.40...9.0.41)
> 1 August 2017
- Fixed symlinks for synology devices when returning show image paths [`ba6f47b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ba6f47bd0727ba7629ef14328b674d2578fd6d47)
- "performing episodes search for showname" message to only be displayed in log if there are actual episodes to be searched for [`8b294f8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8b294f80dbc7de6e4ab58f96636be1ac226f4335)
- Merge tag '9.0.40' into develop [`8a22c30`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a22c30ee3df2c07621179efc05816fc5ebd4f5e)
#### [9.0.40](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.39...9.0.40)
> 31 July 2017
- Fixed incorrect refs in rtorrentlib module [`512bfcc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/512bfcce82ea5e4a93ce6e422cc662b3d607dd45)
- renamed rtorrent libs to rtorrentlib [`dfc5dbd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dfc5dbd4047c46226467b27a5b8ea786dc4e771c)
- added absolute import for rtorrent client [`961db5c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/961db5ca219c964ef3a64b060ca5f7dfe724c3de)
- Merge tag '9.0.39' into develop [`ea576f3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ea576f3e9e33d0e9b10b18e0fdced0c74d7b6c54)
#### [9.0.39](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/9.0.38...9.0.39)
> 31 July 2017
- Fixed issue with nameparser get_show function [`227ac22`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/227ac22fe49b348f181de3baf2b836c63e99be09)
- Merge tag '9.0.38' into develop [`a68d142`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a68d1426b9b2546943bbc49552a0a63f7bf88e5a)
#### [9.0.38](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.37...9.0.38)
> 30 July 2017
- Merge tag 'v9.0.37' into develop [`3e3ed86`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3e3ed8650f25b4ffe540662fe38073ff26b2b794)
#### [v9.0.37](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.36...v9.0.37)
> 30 July 2017
- Merge tag 'v9.0.36' into develop [`820d256`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/820d25657daa68cc5e0939888ad3baad9fac6f6a)
#### [v9.0.36](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.35...v9.0.36)
> 29 July 2017
#### [v9.0.35](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.34...v9.0.35)
> 29 July 2017
- Fixed issue with caching rss feed items not in tv library [`3ebc420`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3ebc420d77eecfbf39e3126dc3e5f89e951fb4da)
#### [v9.0.34](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.33...v9.0.34)
> 29 July 2017
- Fixed code for unpacking rar files [`3b3085c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3b3085c8ee19fd80205cc61bfd9e61f38fc8a026)
#### [v9.0.33](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.32...v9.0.33)
> 27 July 2017
- Fixed typo causing issue with log filtering for post-processing [`77457f8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/77457f83660542ad1234028b5ef1ca1c0295d1d4)
#### [v9.0.32](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.31...v9.0.32)
> 27 July 2017
- Misc code improvements [`1898db7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1898db76c996ce90d9c515ae2cb11e206416e649)
- Fixed typo [`6ac10bd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6ac10bde9de6f3c4eb2c80cacdcc214d8a08df07)
#### [v9.0.31](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.29...v9.0.31)
> 25 July 2017
- Fixed issue with selecting too many shows when adding existing shows [`bf579c6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bf579c677cf99e410e3f2caaa3d770fccebf85a0)
- Fixed show image scraping issues [`a492e7f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a492e7fcce5e39a918b1f232670456b030301456)
- Removed lxml from requirements [`564f31b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/564f31b756b4e5f2ac95596e7e3cf51c3d16ad90)
#### [v9.0.29](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.28...v9.0.29)
> 23 July 2017
- Fixed issues with connecting Deluged clients [`fdea81f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fdea81fc17119595989777f9f538f0c9d9be36cb)
- Fixed issues with Deluge WebUI client [`8539ec9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8539ec948780b0214ca1d357e069da7ec53af694)
- Fixed issues with provider url's [`02a28f7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/02a28f7d59357283e5ad72f84f9fb1efc6c84a99)
- Cleaned up morethan.tv provider code [`3543398`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3543398a9816d9e9a6a8522c7ffc22ac7ad9cfe8)
- Fixes session issues with cloudflare scraper and web client session request function [`341a7eb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/341a7eb4c94e5aaba30c474248d0a16145f4c59a)
- Fixed issues with sessions and cookies for providers [`5e99b21`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e99b21701ca7bbfb2e407eff55b8e90d7f823de)
- Fixed Unicode issues with general config page [`45170ac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/45170acb582f1bc7cc330e8fa9de2278afc6ff62)
- Fixed issues with scene exception downloading and name cache [`7f1bc8f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f1bc8f9df430203f04a1eb4991e1f4cdd2e8ec7)
- Fixed unicode issue for displayshow template [`761353a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/761353a35dbab96b65f780390574dc9dc7d07a5e)
- Fixed issues with web client sessions not being persistent [`47afef8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/47afef8b3f7946f57805e56ba82b095aeb3462a5)
- Fixed torrentday url [`22ffaa3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22ffaa3e159dee5a8e5caad9b8367a03c2e0c9a3)
- Fixed torrentday url [`32ed9c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/32ed9c74a9ee7bd3467f9a9cd4eb678993767f0e)
#### [v9.0.28](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.26...v9.0.28)
> 14 July 2017
- Moved location of libs folder [`4731b6a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4731b6ac96c3d79a5418b78861d62c8e8ae481bc)
#### [v9.0.26](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.25...v9.0.26)
> 14 July 2017
- Cleaned up filtering for mass update page [`672730d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/672730de49fe83ac807e58dcb2806786c8a97fe1)
- Cleaned up filtering for mass update page [`765d71f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/765d71f7c98185488c83362204d4c19432a2ef77)
- Misc improvements to show queue functions [`28e9e8b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/28e9e8be1255fab83b438fabc0052715b58f2db3)
- Updated manifest [`abac6ed`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/abac6ed97b75eb1c4a2503b1f1db6c58524795f5)
- Updated bittorrent cache urls to use secure links [`f712802`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f71280279c37a84daf8ffec54dfbd50413146355)
- Download size filter now displays size of download and quality size when throwing exception to ignore [`6687cd7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6687cd7fb1d34742a3095c991d32eb98ce60a538)
- Updated setup file cleanup code [`4be05b1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4be05b14121b9c47b358249d67b89f806ec1eb27)
- Changed network timezones url [`1be8b99`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1be8b9998800f643c80ab47aaa9629ca4000f9eb)
- Changed scene exceptions url [`1efad19`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1efad195815cf883c06b00e3f175fb4e0337419b)
- Fixed exception error for filtering sizes of download results [`b0c4125`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0c4125607322a340532ce7224ac5082d2888c2f)
- Changed anonymous referrer to nullrefer.com [`8eed07c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8eed07cac3e8d847595ca53bb389b7b13acf7428)
#### [v9.0.25](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.24...v9.0.25)
> 14 May 2017
- Fixed issues with post-processing air-by-date episodes [`1d137a2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1d137a252f92e8bd3bd168e4c82d9b05205b9411)
- Fixed issues with web sessions [`537e7e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/537e7e473eb2c0838362e6d7ffd93f26cf96d75d)
- Fixed unicode issue when deleting shows [`8a3edc5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a3edc51f19bebb5e8244c2acf7629acd1dca8f2)
- Fixed template issues with manually searching previously snatched/downloaded episodes [`8af7715`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8af77150fbda4a930a02b1017b52db28c56e4fdb)
- Fixed web session caching issues [`ffe7b30`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ffe7b3043fb03d14d57157a87f8be2508f7544c3)
- Fixed web session caching issues [`3ff85b7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3ff85b70af8d992efe2cbdea884325174da41b6d)
- Fixed typo in scheduled job name [`461c001`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/461c001575226fc4fce57011e213d4395803e5bc)
- Removed obsolete images [`ec4bc83`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ec4bc830816007f215a0c34e8263818698bcb1db)
#### [v9.0.24](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.23...v9.0.24)
> 9 May 2017
- Updated readme files and gitignore file [`d40b187`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d40b18790122b8f9f96d4cda66361b32d72f3ad8)
- Disabled web session caching for provider searches to ensure all data returned is current [`7c4bf39`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7c4bf3930c93bac7275310a29be317fea76fb755)
- Removed 7 day cache for web sessions [`ec347b0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ec347b0da197a63845be06affb5f0f2b6553e991)
#### [v9.0.23](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.22...v9.0.23)
> 8 May 2017
#### [v9.0.22](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.21...v9.0.22)
> 8 May 2017
#### [v9.0.21](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.20...v9.0.21)
> 8 May 2017
#### [v9.0.20](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.19...v9.0.20)
> 7 May 2017
- Cleaned up next episode function code [`7269f08`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7269f08ab4bc83d339298f781ea8ec1a016a1d8d)
- Fixed view log search issues by adjusting regex opts [`f9f2cd7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f9f2cd74b9ac80246e18f675e5c183c274629f63)
- Moved nextEpisode function call for daily searcher to searchForNeededEpisodes function [`4721bb5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4721bb5c3a2e659b111ebbb7b73c0e1f68eb881b)
- Removed news from list of default homepage choices [`e412510`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e4125104d587e8b9bed89ca1db637d479877f5ba)
- Fixed view log text alignment issue [`bc5f92a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bc5f92a9a5064ec79c186c0cf5134e8ae0caee50)
#### [v9.0.19](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.18...v9.0.19)
> 7 May 2017
- Fixed issues with buttons being hidden on log viewer [`39e1a19`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/39e1a19556cf6f0eb3df71a35fff50b0958be25c)
- Fixed issues with launching browser on incorrect ip address [`112d3a9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/112d3a946522ce1f69972fc5d57c780c10df4aaa)
- Fixed downloading of torrent files from hanging when issue with connecting server [`3e87d84`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3e87d84d962e2670b89b5b7eed18e49c4ca03bc2)
- Fixed issues with daily searches and episodes without a name causing pattern match errors [`da83091`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/da83091b857347c247959767f330fee911fb41b5)
- Fixed width issues with display show page [`6f7f317`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6f7f3174f27eaaa70d4b86bd4bfa7a0c6cce567d)
#### [v9.0.18](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.17...v9.0.18)
> 6 May 2017
- Fixed misc unicode issues [`71d381a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/71d381a4c2147fedc3b69faddf6e65d19c6910a5)
- Misc code cleanup [`49359c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/49359c4afbb5a0af8ef22c9e88f970faab66f383)
- Fixed update notifications for source updates [`4924eca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4924eca60da0c0cd1249c37b41022e20dc58b499)
- Fixed update notifications for notifiers to display new version [`85bd7d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/85bd7d72339da971f4e3316e64ca3e87b9cd957c)
- Fixed global name 'get_lan_ip' is not defined error [`4c9b49d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4c9b49d3a1a55127348f726f92da29c0ceb7a16d)
#### [v9.0.17](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.16...v9.0.17)
> 1 May 2017
- Fixed issues with qtip js code [`6a10c8e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6a10c8e397f11a29659d6ef769dbbe86b1afb8d4)
#### [v9.0.16](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.14...v9.0.16)
> 1 May 2017
- Fixed display show table layout and column selector [`bbab0a7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bbab0a773b8e9ff4650353ac05105bf13bd66584)
- Updated tablesorter to latest version [`88ace11`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/88ace11b32b1b210247f01b6304a80818a788a01)
- Make upgrade notifications to be 90% of width and responsive [`f2e439d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f2e439daccd7b8dfffef5a3cdb808cd96abf50bb)
- Fixed season checkboxes in display shows [`58b2dae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/58b2dae46feb27832d1db648da38ab39d3a13f7a)
- Fixed issue with 'prev episode' on main show page [`63ba9db`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/63ba9db32be931f5900400ad5ae50c0cf1e5fe23)
- Moved upgrade alerts to be positioned below submenu if exists [`ec48add`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ec48add932e3050e093f3fc6e52497e2acc4eb07)
- Moved update notifications code to views updateCheck function [`2ff8f73`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2ff8f73becd1a337a1d81ad8843ac2988da97599)
- Clears newest version text variable before redirecting to restart page on updates [`9446ad4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9446ad4cc585b89514de0b41acb1c90c2aad4bcb)
- Fixed column selection issues for display show web view [`1c72547`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c725479da7633cd7ef2f604a8bda0b3a180b5a9)
- Fixed forced update checks to display new update text even when autoupdates are turned on [`410c93f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/410c93fad94497f24231c57de8a19f8b47f28be6)
- Clears newest version text variable before redirecting to restart page on updates [`69f604d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/69f604d4e1f2bbc160d44025c794ea09e96d174b)
- Released v9.0.15 [`c111307`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c111307c54fc8589b380cd5ffb6ef013490fa3c4)
- Clears newest version text variable before redirecting to restart page on updates [`7d2d7d8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7d2d7d8c313dbfb43198b58ac74f7148ca9a8949)
#### [v9.0.14](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.11...v9.0.14)
> 26 April 2017
- Fixed tabs for notifications config template [`c2983f8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c2983f89e75a8719a2068cf79b21bbd858f31f84)
- Fixed tabs in templates, reformtted templates [`02d0a89`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/02d0a89a917df1aeb524673ccbd7af9ab24b6b3f)
- Fixed tabs for post-processing config template [`e9f3913`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e9f3913ede32994cdad52c65b24990bbb13ecc38)
- Fixed tabs for search provider config template [`4e4ad23`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4e4ad23ebcfcf38b638ca0f6096564c172f0b9bd)
- Fixed issues with subtitle config template and adding languages [`b1a5276`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b1a527624deba8a9f54e7ca1c0b2c4bc41a994ba)
- Fixed issues with editing show info and saving it [`cfd1b33`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cfd1b33011687f8d113261d32231d8cb37d81f38)
- Removed news functions [`c603415`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c6034157bdbedc91ebce6a5d799cfed6e6910ea1)
- Fixed tabs for search provider config template [`9eb7122`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9eb71220630e5ad10c01581a9bd819d5f81088b1)
- Fixed issues with returning the wrong interface ip address [`2c722b7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2c722b760c4cfbb4ae75ac5bad194c9bfc932099)
- testing new restart code [`71d7bdb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/71d7bdb0b8823b30dea62d010a1f29ad3ba4aa58)
- testing new restart code [`7cf729d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7cf729db6d41ffd84adb16750989aa798ab71886)
- Fixed issues with enzyme exceptions [`2f73691`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f7369100eb2709f726b90c719cfc2b7ea631e44)
- testing [`256b107`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/256b107dcb178523b7ddd35ed1a4ec68d0514180)
- Fixed version updater issues [`c96a482`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c96a482fea5ba222ab511c20f5a1e61da5f660c0)
- testing new restart code [`14cf887`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/14cf8875fee561ef6ebe47710999da12dd1bed26)
- Fixed version updater issues [`62dfd77`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/62dfd7765b90cf45d3b74a8a01237433fe4b2100)
- Released v9.0.13 [`b1eeac6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b1eeac63c558d1f8eb0c7709d70331527ede0d30)
#### [v9.0.11](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.9...v9.0.11)
> 18 April 2017
- Misc changes [`01b56d9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/01b56d966d525270c704f3253ae914e7c8c8b1a8)
- Changed layout of display shows template [`4a93dfb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4a93dfb05faed7990ea5f40c976c14f626486f4e)
- Fixed layout for history template [`c4825da`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c4825da992c5a02893afcc2062f38dab60830d4c)
- Fixed issues with navbar and anchors [`46a6106`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/46a610668718abd89de8a2f6000b5947099760ac)
- Misc changes [`245f6bf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/245f6bfcd30af2a4a8d1b096a2c03f23455fcb7a)
- Released v9.0.11 [`1259eb2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1259eb237e58a780d2b8c3bba7fc007488e6a176)
- Released v9.0.10 [`6822e6d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6822e6d1fcefe15ae476fe3252962e31da6ab380)
- Changed display shows background from poster to banner [`3771cf2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3771cf28b679603ce7c23316cebc50fa165faf82)
- Fixed show overview attribute error [`4a4538b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4a4538b708d3608726a78ca978fec7b7fc895c2c)
- Fixed show overview attribute error [`e12ff3e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e12ff3edb9705773dd29e831a92f477a32846eba)
#### [v9.0.9](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.7...v9.0.9)
> 15 April 2017
- Converting display shows to popup modal [`f9ad610`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f9ad61047cef12fc8505d544b7c39dcd9be2e342)
- Converted display show template to be responsive [`6f8a986`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6f8a986481ccce539120029fcd9728d402720e5b)
- Removed FancyBox [`572ada6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/572ada681a780287e3f7468392d847cee3af5d39)
- Removed unrequires loop continues in templates [`46d5408`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/46d5408eded50aa907200d102c7fc1d77c47dce2)
- Removed unrequires loop continues in templates [`8b9b81a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8b9b81a22f19d9430139a09b9cdb0e68ab4169b2)
- Removed FancyBox [`ef7074c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ef7074c17da56320f363b2183732c2485b343ed7)
- Fixed issues with web root variable and reverse proxies [`02bcefa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/02bcefa67b685c40921ece6940d79f98fed77a0a)
- Updated responsiveness for display show template [`681aee3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/681aee3ad3f88fe0d0dbd98e0a08c28dddced7de)
- Removed unrequires loop continues in templates [`19fe437`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/19fe43792a40126f58629a874be54f44e8884066)
- Performed grunt tasks [`34fd2d5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/34fd2d58223640b69d7e9b2979125f4fc589a5ce)
- Released v9.0.9 [`e126a23`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e126a23606bafa254dc46dc34b65ec8f5fafbaf7)
- Fixed url paths to image files [`2f7163b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f7163bcc61706e6ab8c6fed3058b734b549a8fc)
- Performed grunt tasks [`9941ce1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9941ce1d043d6f24036c652cf96ccc7954db291a)
- Removed showing imdb runtime/year info, uses show runtime/year instead [`010345a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/010345af90bd51acd348ef274b14763ebfef12ed)
- Performed grunt tasks [`8b0193a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8b0193a61b8653df238a969d249b8fac63406482)
- Changed notification icon size from 32x32 to 96x96 [`6c7b3cc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6c7b3cc7656ef157a295d773e95fe16f6662261c)
- Removed showing imdb runtime/year info, uses show runtime/year instead [`4f851b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4f851b306b6f965b236c7d4b368e406e701a588a)
#### [v9.0.7](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.6...v9.0.7)
> 14 April 2017
- Updated favicon's for all devices [`b1edb65`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b1edb65414fddd6f00d98400ae93c3d35acc6895)
#### [v9.0.6](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.5...v9.0.6)
> 14 April 2017
- Removed unrequires loop continues in templates [`73e78d3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/73e78d336cfb6ea06a6467862623cab41281196d)
- Fixed issue with quality chooser template [`0ab30ee`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0ab30eea4ecd2adaaef89bd5307443ec1a69af2f)
- Use showObj when referencing indexerid [`4a8fc9c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4a8fc9c94d6c8019cce01e3245504d6bbd6a7bd1)
- Fixed issue with quality chooser template [`d0aebf1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d0aebf139614b0a0bdcb3e730badcc56ce8967bb)
- Grunt tasks performed [`53076ab`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/53076ab3dbe7f7c91431785491ed591b8ee462d2)
- Fixed regex for web server images path [`a16c75e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a16c75e0814d454386fd8d272edf01626bd109f2)
- Fixed issue with quality chooser template [`eba7fc2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eba7fc2d3b8633ab20190b871c9cc17539ac1b31)
#### [v9.0.5](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.4...v9.0.5)
> 14 April 2017
#### [v9.0.4](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v9.0.3...v9.0.4)
> 14 April 2017
- Released v9.0.4 [`1aecdce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1aecdceebd6901b099380faa6a78047d9439075f)
### [v9.0.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.8.4...v9.0.3)
> 14 April 2017
- Misc code updates and cleanups [`dbafd0b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dbafd0b1e3584839c8698d9cd8c3366fa2772508)
- Moved custom libs folder and added in code to add to python libs path [`cf5506f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cf5506f59ba76e9f8880b6e341bb0fcd8b2b9afb)
- Cleaned up subtitles code [`17f64bc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/17f64bcc6d3a2a079312d83a708c32b10cd4d360)
- Migrated to new-style settings for metadata provider objects [`ab88a54`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ab88a5484bcf157d15d5c9ee162f9ca8e2f089bd)
- Reformatted and rearranged code [`e4d8300`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e4d8300d49676e125b7eebb013a2238347007cc8)
- Cleaned up home and scheduler views [`13dea70`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/13dea70334639a886a9dff60b0a603396810f155)
- Updated provider URL [`b8fce94`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8fce948bd124c8dcfd2bd2c4b4b70d33f571f71)
- Migrated old-style notifiers code to new-style with generators [`4658201`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/46582019d69682313e8de08a947808eb3202d00e)
- Fixed issues with web root variable and reverse proxies [`5d0de31`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5d0de3105c1e75df1072715a88e7e9842e97c66a)
- Updated subtitles downloader [`40ddccc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/40ddccc8b365acc3fdbfdb7e97e681584634a1c0)
- Improved daemon handling code [`80e464b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/80e464b7969f526c0c68199871c00e194559967e)
- Misc code cleanup [`ef6fc73`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ef6fc73ad61f60719d4172fc64c6c7f1d362a221)
- Misc code cleanup [`338f1e5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/338f1e533feaf6a9339da5b58206961bdef1b2f7)
- NEW Release v8.9.8 [`64be91c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/64be91ced953ad24fd9da1a0125aac95c4942938)
- Improved daemon handling code [`05db96b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/05db96b0f0205e9ccadb555bcb8c8f5fd26ea722)
- Updated code to help debug issues with metadata downloading issues [`033ca62`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/033ca62c7d85cf389d031e978581ec0200d2597b)
- Fixed misc bugs with web session handling/exceptions [`e29e5bf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e29e5bfb50abfd1c73f206bf0c1a4bc875a069ba)
- Fixed issues with startup delays related to compacting main database [`f042119`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f04211961c9cb886c4a4ae219ac7a5c325ec5d4b)
- Migrated from os.rmdir to shutil.rmtree [`c77b996`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c77b9960ef563d9882b3c74f245676065373702c)
- Cleaned up web server init code [`fbb3999`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fbb39992eab7b14612a966b5f35ef670ec1a8359)
- Released v9.0.3 [`5c1022e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5c1022ef6a39cb46cdbcb80193d91d6a70fb81c4)
- Developer mode disables scheduled jobs [`8ab1894`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8ab18941e5bc4e8d3bea137aceb27872f98644f6)
- Fixed issues with core session download function [`31d5fe9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/31d5fe91a34d292b6e675819b373f17af1b933f7)
- Removed misc stale code [`d4061cf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d4061cf2efb5c70cb43115ba65ae8f6afbad801f)
- Cache directory is now automatically placed in data directory [`bf1768c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bf1768c3e5d32b6257ce930835f2fbbdc8662c8f)
- Cleaned up version updater code to reduce memory usage [`639ce93`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/639ce93bdffad0fcd2efd8e555ef7fe38b6c5ffb)
- Fixes issues for corrupted thetvdb api cache [`b27f5fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b27f5fefdb3a01981e6d106aa3f01433492fa96b)
- Updated thetvdb api url [`6086b26`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6086b26a751afc63f6d989448718fe8a1bd872d0)
- Fixed issues displaying episode end date/time in schedule view [`59d69d0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/59d69d096fcf24cc03f35e119dfc40c3b7d29452)
- Fixed issues with new subtitles code [`417d5e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/417d5e2e09aea3181b4ae6c160786d035e28caa3)
- Corrected some code violations [`7c1e6b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7c1e6b233eacea7353641f2c2500d3df0e36baa2)
- Fixed issue with metadata view template code [`3f87196`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3f871960c871252bb7ea423bb939459344fe9d29)
- Fixed import errors [`04dd3ef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/04dd3ef2ec855db3ec2fa2ab4c4a435230feeb4e)
- Fixed queue currentItem ref's [`d669135`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d66913531d5db29dd60128c999863ecdc0a6e901)
- Updated requirements [`7f2b8cf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f2b8cf96790bc8b85052f05f2c1b556c4783796)
- Fixed template error for app status [`e1e541f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e1e541f6a510320c4f700e0743fcc7cc53f2f50f)
- Fix for failed downloads [`39b7cd5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/39b7cd5fc8e56871a89ab4d8a9a0c014204f8480)
- Increased indexer api timeout to 120s [`a7d9214`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a7d9214fe0c8a00569822fe10a588601f9615364)
- Optimized Imports [`40fd11e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/40fd11e345e061e214e620822c0f19c29cb400f5)
- Improved daemon handling code [`5e0d292`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e0d2923da0b5dd1d693377faa9722855f25f685)
- Changed threading lock to rlock [`5ab4758`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ab47583e2e3b84e9289b84b1ebb92a3a70889b4)
- Removed the ability to change the log directory location and log file name [`9ee5c8c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9ee5c8cf4dce2f2b8ec4ba1281d897e8395529cb)
- Fixed issues when trying to retrieve images and actor info from thetvdb api [`b278192`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b27819244d82ca3653bfed79a8a3866e46e29a18)
- Updated code to help debug issues with metadata downloading issues [`e530100`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e53010038bf5661f6086d532f5db580b9bda67b7)
- Fixed pushbullet notifications [`e563457`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e563457d6de23108ead408e6cd13d48105855359)
- Fixed db backups to save correct path names [`ce5ff24`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ce5ff24e52208c9f1616c9956e1f89483366f97d)
- Updated contributing guide [`b2af322`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b2af322771c22ca6f88973d2e7258f06e9760e7f)
- Improved daemon handling code [`785ccca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/785ccca8a897e1990b7f49056f1fc4c1eced6dab)
- Fixed queuing priorities [`1a863e5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1a863e5b55ee8a4ec1810a3ea3be50c54fa0bdf4)
- Fixed args passed when in daemon mode for browser window launching and quite [`13ef587`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/13ef587b49336271eb6a99055e50dfe17540d5b0)
- Updated code to help debug issues with metadata downloading issues [`b5633b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b5633b2057111d5a20d526ec32884f9cc2c53b07)
- Fixed issues with version updater [`5e2dd84`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e2dd843c6fd8b2d4d836823eef8917be71f3f50)
- Fix for pushbullet configuration in webserver [`49648be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/49648be184e3d81404933789fb288d90227b6e47)
- Fixed issue with parsing show airing info from thetvdb api [`ae89023`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ae89023c180e157a8c654fa4c445a1cecfeaf46c)
- Improved daemon handling code [`55d69f7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/55d69f7d5d66da1349534ff189bdfff28ff8a83d)
- Fixed issue with saving metadata provider settings [`d791a3a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d791a3a853b5555344f6a765bdeaa694c11c90f7)
- Fixed issues with next_ep and prev_ep airdates for home view [`3a1a2f5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3a1a2f5db74f8176337c6e4a1c693b37719432bf)
- Fixed issue with season pack searches/downloading [`5dfb0b1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5dfb0b16b16500b49b7e861836acf4676146b094)
- Fixed issue with parsing show airing info from thetvdb api [`0e3cda5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0e3cda58d6148c15ad0ed5c13f680f4127af6402)
- Fixed issues with displaying providers [`2694d7b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2694d7b8ee9a386cbed32828f0c7a1b9269ab168)
- Updated requirements [`6a75c06`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6a75c06b0151f0264ff8335b70c1818185ba79aa)
- Corrected some code violations [`5e53d4a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e53d4a0de4e99212fc8bb0e226a42328193ec8e)
- Fixed issues related to renaming episodes and subtitles [`82d5a2d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/82d5a2d759fb3784a88c6cbb26d84d227b3d4682)
- Fixed issue with episode status manager and snatched. [`613f601`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/613f6015cc3cf37a52320851ad72c5e0f8276eff)
- Fixed pushbullet notifier web sessions [`5459e37`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5459e3732b3921d2fa4cd3dc7fb486311bf12271)
- Fixed issues with automated show updates [`8be82eb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8be82eb4966b1329acd8e6e22646219b35f19312)
- Fixed restart issues during updates [`873a209`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/873a209c87878f7898d7252ec33f8340a4ccf6d0)
- Fixed issue with version updater and safety checks [`45a38c8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/45a38c873467d6e13d603e3cbdbc06ba34502ec3)
- Fixed login redirection issues [`c60690a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c60690af661406ab48bf6329f2c266ee07a24e1e)
- Misc code reference cleanups [`d2d7244`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d2d724480bfcabbd9a412f5c3ab9b62286a7a203)
- Fixed issue with provider objects and ordering [`6d06475`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6d0647571916ece9b18fb97878ed548b04d9f3be)
- Released v9.0.1 [`fb0e818`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fb0e8189081041cbb09eb03a227e660f0fed1e75)
- Queue threads joined on shutdown [`14ce167`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/14ce167d4017e0a1715eef52b469dc991d60a622)
- Removed startup message for daemoning pid [`3edf433`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3edf4331528b20629ba453faf4c2ae016cefbf4c)
- Fixed insecure url [`7f4b642`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f4b64248b11eaf84c1960680e415562bca5026b)
- Updated to v8.9.4 [`10d0371`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/10d0371b32eeba07919346f1ead69b4c1d0cb5b8)
- Updated to v8.9.1 [`76a3681`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/76a3681b05ef3309544a2203106e6385e390fe63)
- Updated to v8.9.0 [`11deea3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/11deea3bff269fb660f57e64163250d715f98947)
- Updated to v8.8.9 [`70aa230`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/70aa230393302a910d3063a98c6995c425ecb799)
- Version updated to v8.8.7 [`fb84609`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fb84609c7ad76bae5fe5c6f9b12a155a6c9ef9df)
- Updated to v8.8.6 [`1594ffe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1594ffe94b162f998bda61f08061477fd9eba574)
- Fixed provider URL [`50fe40a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/50fe40aa88a5256a88224431bebfc9405286c3ee)
- Fixed issues with next_ep and prev_ep airdates for home view [`8456556`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8456556b804d2f61e421d4d3a887c358135fb675)
- Improved daemon handling code [`0333c4c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0333c4c2d3d06da95ee5d009d3f9f9a3dcb4ba47)
#### [v8.8.4](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.8.3...v8.8.4)
> 15 November 2016
#### [v8.8.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.8.2...v8.8.3)
> 13 November 2016
#### [v8.8.2](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.8.1...v8.8.2)
> 13 November 2016
- Fixes issues with Newznab providers and dict key errors for feedparser [`2a0f78f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2a0f78f2c633729c23d4e7eb3b531cfa746320a0)
#### [v8.8.1](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.8.0...v8.8.1)
> 13 November 2016
#### [v8.8.0](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.7.9...v8.8.0)
> 12 November 2016
- Fixed issues with omgwtfnzbs newznab provider searches [`671670d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/671670d811592de5d10bcf3bb3644f66089c87fe)
#### [v8.7.9](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.7.8...v8.7.9)
> 12 November 2016
- Fixed show display template code [`45d8ad2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/45d8ad23aee15f65c166e98b006ee4b6de3a9bcb)
- Fixed issues with find propers searches [`1f80a6f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f80a6f3cb52331effc763fbd5cebcd7afffd291)
- Fixed show display template code [`f153e72`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f153e720a63901a08e40ad89435039bf2fd55eb7)
- Fixed issues with find propers routines [`5726d5f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5726d5f6c7251250f62ea519835899ecef6e189c)
- Fixed issues with database and too many files open error [`bc7184c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bc7184cb9bbf3ade8c2a71a4c78c07b3f3c7d762)
- Fixed issues with database and too many files open error [`7ad7d01`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7ad7d010d40749e7e674de01994036fae6b47933)
- Fixed show display template code [`bde3888`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bde3888c068482f57a81bd292373add9cb563941)
- Fixed show display template code [`8acf7b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8acf7b33ced8d64a354217880370a01da9d61576)
#### [v8.7.8](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.7.7...v8.7.8)
> 7 November 2016
- Updated logo [`a546517`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a54651757b24f23bb9f41c7ab795cf9f442499c9)
#### [v8.7.7](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.7.6...v8.7.7)
> 7 November 2016
#### [v8.7.6](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.7.5...v8.7.6)
> 5 November 2016
- new: v8.7.6 [`35db11d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/35db11d7a3dd34572f6c72fdec6da40f88c3a841)
#### [v8.7.5](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.7.4...v8.7.5)
> 4 November 2016
- new: v8.7.5 [`eabff6e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eabff6e8ec8c61dce13ac20670b111f97fe318b2)
#### [v8.7.4](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.7.3...v8.7.4)
> 1 November 2016
- new: v8.7.4 [`1140fde`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1140fde8270118a0a8047e6293d485c429766dec)
#### [v8.7.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.7.2...v8.7.3)
> 1 November 2016
- new: v8.7.3 [`7df9a11`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7df9a1187b39229d5c6d17db5d1af1d9aacc51ad)
#### [v8.7.2](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.7.1...v8.7.2)
> 31 October 2016
- fix: Cleaned up version updater module code [`2af3779`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2af3779d5b9fc283f1fe3d3d6b8953e59f4becb8)
- fix: Cleaned up nzbGet module [`cdc56b9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cdc56b9d57862478ebbca292f394281a2fd7e144)
- new: v8.7.2 [`25c7e45`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/25c7e455d1fa830a2f69ce8166ae819cd2f51e5a)
- fix: Cleaned up code for finding shows in show list [`2f74a8b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f74a8b48f2e9f02465d6c230d0d3cda8c7f9f6e)
- fix: Database backups now done for each database, 5 backups per [`5b4ae73`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5b4ae7369053f5bd6cec9fb5476db61999256fb5)
- fix: Cleaned up template for new shows [`ca9a483`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ca9a483494882fc5c02a4341264bedb0b9e08ab2)
#### [v8.7.1](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.7.0...v8.7.1)
> 25 October 2016
- new: v8.7.1 [`15d2930`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15d2930614366657db26191ca77503a7271fec8d)
#### [v8.7.0](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.6.9...v8.7.0)
> 25 October 2016
- new: v8.7.0 [`f385fce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f385fceb4fb30defd5cf009ad43150da6e95ffd6)
#### [v8.6.9](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.6.8...v8.6.9)
> 25 October 2016
- new: v8.6.9 [`862a810`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/862a810a34c5381f930ca9cc5a0a591983e29d85)
#### [v8.6.8](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.6.7...v8.6.8)
> 25 October 2016
- new: v8.6.8 [`d0d9a70`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d0d9a70e9684d752be8c911747c4af4041c4138b)
- fix: misc url changes/cleanups [`179d46b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/179d46bfb28430488b02b55e621080252726e98c)
- fix: misc url changes/cleanups [`850f2be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/850f2bee57e909ea50566909841a166f1df566bb)
#### [v8.6.7](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.6.6...v8.6.7)
> 23 October 2016
- new: v8.6.7 [`a6bdbdb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a6bdbdb51d7786da9abba8faed5cb7b6a534b32c)
#### [v8.6.6](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.6.5...v8.6.6)
> 23 October 2016
- new: v8.6.6 [`3405193`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/340519363a27bc4a30bc8c8ace453c2ecefe5791)
#### [v8.6.5](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.6.4...v8.6.5)
> 23 October 2016
- fix: Misc cleanup of code and headers including url updates [`99fb372`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/99fb37277daf8bce54273b3128347117081745b7)
- new: v8.6.5 [`437e2be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/437e2bee6a0ef0a1c0611b1ba4803daa6cfc9ed8)
#### [v8.6.4](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.6.1...v8.6.4)
> 22 October 2016
- fix: Fixed issues with saving providers then having incorrect attributes showing [`002de48`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/002de486dd56cb00e14e98419303b458dd0328ac)
- new: v8.6.3 [`e5f0fae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e5f0fae1bdfb6c501460547f4a0de6f4f08a4624)
- new: v8.6.2 [`c888b11`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c888b11c9debf58534ac32b8c913f398dc2d9e3a)
- new: v8.6.4 [`4031902`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/403190298d0b71f098d24abcd85bf463903c7dae)
- fix: corrected issue with checking for enable_cookies attribute [`3db5ed7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3db5ed77236faca97410cf9f87b38d3265cd42d7)
#### [v8.6.1](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.5.8...v8.6.1)
> 15 October 2016
- new: v8.6.1 [`c96cfe6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c96cfe6164472b384b51f88ffa51b71a61ccf7cd)
- fix: Fixed proper searcher [`33db42e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/33db42e8a8172d7c665ac73d597450b650fd9dc6)
- new: v8.6.0 [`7fe3d84`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7fe3d847859812097e475f2d52585c544b527039)
#### [v8.5.8](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.5.6...v8.5.8)
> 15 October 2016
- fix: Misc small fixes [`a0f0484`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a0f0484c9c32a7797c1691cb2638748b4e0e715e)
- fix: Minor change (testing) [`5ba5063`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ba50638d9f177c606dd5f240adee6d5b84248f3)
- new: v8.5.7 [`74e09f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/74e09f1da87566b45931ea85acb82d86cf19422b)
- new: v8.5.8 [`b1a92a3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b1a92a34e72b7299dcbec8a97c2027bd62883b2d)
#### [v8.5.6](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.5.4...v8.5.6)
> 13 October 2016
- fix: Misc code corrections [`5e7f7ac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e7f7ac748ca332c1fbfc16b0724692c5456fa4a)
- fix: Post-Processing [`c724b64`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c724b6446ae74d63806213f6c99bad4d40541f05)
- new: v8.5.5 [`416b349`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/416b349f888dad2b03cdedcd54249362c73ede6f)
- new: v8.5.6 [`f7d7168`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f7d716868aa2635d3ed99b8500d5fc9d186ce65a)
#### [v8.5.4](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.5.3...v8.5.4)
> 13 October 2016
- new: v8.5.4 [`1c30b91`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c30b91c0f08c11fda6d54f86591d085a03fe917)
#### [v8.5.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.5.2...v8.5.3)
> 13 October 2016
- fix: RevConflict issue during updating of shows and imdb info was caused by mistakenly storing previous rev info to class object [`c519929`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c519929a98dd4091cbcbf7ff1fd1f71dbd96c25c)
- fix: Changed web session handling of error messages to send to debugger instead of creating a error [`1c7a1ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c7a1baf8c621ca58614f38be39fa7a2cc3fe768)
- new: v8.5.3 [`a337fb8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a337fb8c0a1ae600a1e8a2f3cd64c70b8c08347c)
#### [v8.5.2](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.5.1...v8.5.2)
> 13 October 2016
- fix: Issues with web client sessions due to premature error handling, now returns response object [`9207d6f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9207d6f47ceea5d417e2b750b006f9c1264cca52)
- fix: Fixes issues with git and checkout of new branches [`5a8c514`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5a8c51484f3bb84b08e74fbffbd346409d0b8b25)
- new: v8.5.2 [`5934241`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/59342415116923ce854ed9c1241c1f8524140efc)
#### [v8.5.1](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.5.0...v8.5.1)
> 13 October 2016
- new: v8.5.1 [`d4bc818`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d4bc8186e91537d6f000d9c2ee781e9a0f0c2423)
#### [v8.5.0](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.4.7...v8.5.0)
> 12 October 2016
- fix: Provider code cleanups [`de5b544`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/de5b544c77917fc08832a38bc93e1ae5eb7de0b8)
- fix: performed several PEP8 changes [`462c9e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/462c9e286ea9bb9283a6fdc2ea9fad0494183142)
- fix: Minor code changes [`edf7875`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/edf7875cf420ff90a93f0f348b31532d188771df)
- fix: Corrected typo in function name [`984f4d9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/984f4d98ee58adb3a3c554e66a182f156b7c28de)
- fix: Minor code placement change [`45a8004`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/45a80046e19aa05719f5924c99de74a24ecbc41d)
- fix: Queue tasks are now put into the background to prevent blocking tornado web calls [`ad6760a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ad6760a697c7651cee5c634b8cd839735cc0ccbc)
- fix: request session handling returned resp at wrong section of code, corrected [`2cbd54c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2cbd54c480ba51556836c4f1a7819cce1a3faebd)
- new: v8.5.0 [`47fe22b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/47fe22b85421cae1149229f3b7f119dce78d77dc)
#### [v8.4.7](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.4.6...v8.4.7)
> 11 October 2016
- new: v8.4.7 [`0b6a95b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0b6a95bd33eed54b21583390a27ffa87289e91c2)
#### [v8.4.6](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.4.5...v8.4.6)
> 10 October 2016
- fix: Fixed issues with deleting shows and mapping of indexer's to show id's [`257902e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/257902e8e417fb337ae0ef232a1ef390848dfcaa)
- fix: Misc fixes [`bae6ef2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bae6ef2981646081db8bdebc6c320c1fc956fe27)
- new: v8.4.6 [`baa41ea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/baa41ea031c7c394568927e770464659d188bfa5)
#### [v8.4.5](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.4.3...v8.4.5)
> 10 October 2016
- new: v8.4.5 [`a42520e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a42520ebcc32d7e5909418fdbe3d533fd2dea18c)
#### [v8.4.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.4.2...v8.4.3)
> 10 October 2016
- new: v8.4.3 [`3ca1781`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3ca1781263d4f4bd35d3f6efd705163989f6dec5)
#### [v8.4.2](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.4.0...v8.4.2)
> 10 October 2016
- new: v8.4.2 [`525d3ae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/525d3ae8ff63920ad16a601003da391cec47603f)
- fix: Backlogs start earlier now [`eb09f3d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eb09f3d97217a880f019882e6c0301830fe10663)
- fix: Converted returned epInfo values to integers, resolves episode renaming issues [`3a87341`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3a87341c5f680bffbc1fd2e67a93ab85204ccd6b)
- new: v8.4.1 [`4df3c2c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4df3c2c83cdbf47dc41482c9ab0d7efa661dfa1b)
#### [v8.4.0](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.3.9...v8.4.0)
> 9 October 2016
- fix: Misc minor fixes [`2754b45`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2754b45452652372a36350a833e417aff89a8ce1)
- fix: Revamped network timezone code, gained overall app performance from this fix [`fee55aa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fee55aa1e7c7e44ba24b9a3bdf2c5feacdb781f1)
- fix: Backup/Restore functions now work with new database and database backups [`3c45ed8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c45ed80a93b59a46bc5797796018922a621cb83)
- new: v8.4.0 [`927d3fb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/927d3fb6fc84e454e6a87c18fd3b238467a65f65)
#### [v8.3.9](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.3.8...v8.3.9)
> 9 October 2016
- fix: Fixed issues with episode renamer [`8ff771b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8ff771bcfbd6b7e47d1bbe18ed8afecbb209dd34)
- fix: Fixed issues with episode renamer [`af04c02`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/af04c02f8758150af088bcb8a136e488b2e30700)
- new: v8.3.9 [`2476793`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/24767932f2b280e0ea20c5190945b725008ff0ad)
- new: v8.3.9 [`bbf088b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bbf088b2591ba47600ae389c78955365a7a9dfa9)
#### [v8.3.8](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.3.7...v8.3.8)
> 8 October 2016
- new: v8.3.8 [`9e46f05`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e46f05418462f598e322571e2a5aecd76f17393)
#### [v8.3.7](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.3.4...v8.3.7)
> 8 October 2016
- fix: Minor code changes [`920455d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/920455d59e6681e3de14c06686c187ba3b6b09c7)
- fix: Fixed issues with retrieval and saving of IMDb info [`f4e899b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f4e899bb92c73592f652c56ac2f814099654faf8)
- new: v8.3.6 [`122bd10`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/122bd10874d9a5d8eb5ab9d85cd3f78214e0c644)
- new: v8.3.5 [`63db473`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/63db47348cab0646acfa16cf4ea2f1369b491d76)
- new: v8.3.6 [`2424afc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2424afc6348ab0470feb4711e9f6c1abade733bf)
#### [v8.3.4](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.3.3...v8.3.4)
> 8 October 2016
- fix: Minor edit_show.mako fixes [`#3269`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3269)
- fix: Removed dbFilename from mako template code [`b90acf0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b90acf04ed8d7153487c54b1f1692a62e7620ae3)
- fix: Corrected typo to resolve key error [`7d4cd4a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7d4cd4a0ec4fd2e4558068345967c2be1d13f86e)
#### [v8.3.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.3.2...v8.3.3)
> 8 October 2016
- new: v8.3.3 [`1c5c697`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c5c69745256cc5c31fb37579d167614d5c4030d)
#### [v8.3.2](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.3.1...v8.3.2)
> 8 October 2016
- new: Version 8.3.2 [`6022bb3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6022bb3cfbd9395f6b10ea92fccbdff234edfb41)
#### [v8.3.1](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.3.0...v8.3.1)
> 8 October 2016
- fix: Issues with image query params resolved [`2eeb509`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2eeb509260d00e2ecf0f60b3c81caeaced859fcb)
- new: Version 8.3.1 [`4b278f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4b278f62f49f1ecaf52edf47b01227df11a2871d)
#### [v8.3.0](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.2.4...v8.3.0)
> 7 October 2016
- fix: Fixed IMDB Popular shows page [`4244405`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/42444052415defab343c278a939e214f04f2da79)
- fix: Core queue is now multi-threaded as well as queue items [`2d9625e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2d9625e13815075c59387bd20a29b2a06ec9e3a1)
- fix: Corrected missing DOC variable indexes [`2363878`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2363878233372ccb4959366c440426ba4f3d28da)
- fix: Fixed core queue code thread naming [`1f4bfc0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f4bfc0a1ed2de8f0dc75f891c7c965175b1f959)
- fix: Misc code corrections and fixes [`cdf2d4a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cdf2d4a996a8e2e2b40f4517f1529ab03bc2961a)
- fix: Core queue is now multi-threaded as well as queue items [`60d2c66`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/60d2c66dae95b5f78d073f812f52bbf0f967181b)
- fix: Using get calls for loading episode values from database to prevent key errors [`1e41339`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1e41339c594777365b95f0cb9007db988ef998b5)
- fix: Fixed scene time provider search [`f425aca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f425acaa6f275547799871f9ada004bd1c694307)
- fix: Corrected search queue code for putting search items into queue [`1d4be98`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1d4be987d81d76f34afbeb0c315fde46290fd3a1)
- fix: Ctrl+C now performs proper shutdowns [`c8a3b77`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c8a3b77b643ddb6c7443ff3647af3be5acc81e76)
- fix: Corrected old code for show location to new-style [`ad28896`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ad28896ba1d067eda9db1e7205b2a524afdf0f46)
- fix: Corrected name cache code for clearing cache and properly loading database items into dict [`9101f35`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9101f3561b311ffce9997a403d8b478b2bcab4b5)
- fix: Core queue is now multi-threaded as well as queue items [`c22d84d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c22d84d6f2fdae309ccfe5c004671303db40d74c)
- fix: Check result returned for dailyer searches to prevent issues with adding to results list [`dd02f40`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dd02f409862784152be26a06ef72b1a1982a20b9)
- fix: Fixed issues with scene season, episode, and absolute numbering for database [`d4c2bb7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d4c2bb7c67ec2be12343cb6c8dea188e4202bcc8)
- fix: Corrected missing DOC variable indexes [`987c3ee`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/987c3ee3f519a4c75e49ada1a641f24c9e34b294)
- fix: Fixed core queue code thread naming [`cde2043`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cde2043c204f3ebf69a9ab16328d6e5910de1e29)
- new: Updated network logos [`9eb4be1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9eb4be1748a5d8666049118bbd11564d1344c054)
- fix: Lowered sleep timer [`c3fbb84`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c3fbb844c1cdd91f98382f6b5e76116da78b9ad8)
- new: Version 8.3.0 [`8dad800`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8dad800ae93e7ac77f1a7f77ab9a55672de041f0)
- new: Updated images [`7d3fbea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7d3fbea1304ffd29d862143ed1fcebfeb7bae4e0)
#### [v8.2.4](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.2.3...v8.2.4)
> 23 September 2016
- new: Version 8.2.4 [`7115c4e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7115c4e4ca266b989eabdc3a57b6b5f8989d85f0)
#### [v8.2.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.2.2...v8.2.3)
> 23 September 2016
- new: Version 8.2.3 [`d988a71`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d988a71912d51f2da40276b64d95f208686b320f)
#### [v8.2.2](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.2.1...v8.2.2)
> 23 September 2016
- fix: Revamped core queue code [`b8b6d0b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8b6d0b0e294a4ca5fdbe29d30082ec839d93f92)
- fix: Changed code for restarts and shutdowns [`6b4c6f5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6b4c6f5522e8c534f56021d341b75ee4fce5277b)
- new: Version 8.2.2 [`29d7d25`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/29d7d25aef05810e3a85374f26697130140edc3c)
- fix: moved shutdown of web server to last before ioloop closing [`9617086`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/961708673c9b8dc83969123968ca9e4e987eb30d)
- fix: removed clearing of ioloop, caused fd value errors [`329f2ef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/329f2efebf11b8f9bb1a55c6a29f4319461a7859)
- fix: clear ioloop instance instead of current [`405ea0e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/405ea0eb1e2c0b7cd67ffb95162dff29a1761e08)
- update: Updated tornado requirement to version 4.4.1 [`2a49dbc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2a49dbc2a2a7ddc9ec3607019199eb5aa3747a1f)
- fix: Corrected core queue code shutdown function [`d968bf8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d968bf870bb44095dd1829413fa7a16a6953c0e3)
#### [v8.2.1](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.2.0...v8.2.1)
> 21 September 2016
- fix: Removed un-needed return statement in code [`258e91d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/258e91d46ab3e8d6a614c4f49a83875d4d351a2d)
#### [v8.2.0](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.1.9...v8.2.0)
> 20 September 2016
- new: Version 8.2.0 [`4f6c1d6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4f6c1d62cd244f0170415ef46fce091daa8c22e2)
#### [v8.1.9](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.1.8...v8.1.9)
> 18 September 2016
- fix: Changed routing code for web view methods to return None if unable to locate correct route and skip rendering web view [`436b17f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/436b17f1fbe7f7e62afd85f747ce3ddde931138b)
- new: Version 8.1.9 [`3e79a8f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3e79a8f121e2b95e9ed67899a8816da349f879ea)
#### [v8.1.8](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.1.7...v8.1.8)
> 18 September 2016
#### [v8.1.7](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.1.6...v8.1.7)
> 18 September 2016
- fix: Correct column span for display shows to fix background [`b773e6d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b773e6d86b7958706b9eb22f96bda520c337acc5)
- fix: Removed error logging during automatic daily show updates [`cdc9e5a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cdc9e5a47a45a664f35945504c7b90189af9eb11)
- fix: mapped parsed json data from XEM to integer, helps checking for indexer id [`d088fcc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d088fccabfddeb15e00ed0089514ee8000d6bc6a)
- new: Version 8.1.7 [`37e526d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/37e526d89d04d887212a69c29c676d6d725248b9)
- fix: Corrected query variable [`e87deb5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e87deb56fd5c77d0eef6135829b786ca13077b1a)
#### [v8.1.6](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.1.5...v8.1.6)
> 17 September 2016
- fix: Changed show refreshes to not be forced during automatic show updates [`6021a02`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6021a027037a7683b589439016d41ade1e263acd)
- new: Version 8.1.6 [`f34195f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f34195f44ba432c81d8668f520d686e00fe56673)
#### [v8.1.5](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.1.4...v8.1.5)
> 14 September 2016
- fix: Removed redirect routine override [`cf2b15d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cf2b15d8ae9191ae96a0e06f5310814c10dc4f53)
- new: Version 8.1.5 [`84f1285`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/84f12859db7b7b3a3bc11d15532defdafdb0c32e)
#### [v8.1.4](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.1.3...v8.1.4)
> 14 September 2016
- fix: Fixed issue with IMDb during adding and updating of shows [`93c2b78`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/93c2b789bbb4327feb1005cf559d1807d9d47630)
- new: Version 8.1.4 [`d6bb6ea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d6bb6ea63b94b874326657883f8437e32730c194)
#### [v8.1.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.1.2...v8.1.3)
> 10 September 2016
- new: Version 8.1.3 [`2dbae19`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2dbae19408db4c05d29769ebcc60506ae703785b)
- Updated changelog grunt task to append to changelog [`15fe75d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15fe75db9f40fcd7b5ac803bc42963733ba51169)
- fix: Bumped DB version to 44 to be compatible with other forks [`b1d4247`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b1d4247621bd5dac1ea744c0b0fb425cc6ed892c)
- Updated url for torrentz torrent provider [`201af10`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/201af10c231cfb7097c0136917ffb0609b2288b8)
#### [v8.1.2](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.1.1...v8.1.2)
> 9 September 2016
- Fixed core queue minimum priority checking code [`d9d2ce0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d9d2ce0d1db8d8f123c80c13848c07cdde180f40)
- Fixed core queue minimum priority checking code [`e57cb6a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e57cb6a07d913850149a7df48ac627848834ccd0)
- Fixed core queue minimum priority checking code [`aa14dc0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aa14dc0071909407e62f05170e9eff7ae8dc4a2a)
- Fixed core queue minimum priority checking code [`eb9f718`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eb9f71853d42b75cb88c35fb141e411a1cc399db)
- Fixed core queue minimum priority checking code [`ce154cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ce154cb15364924528f5f7196f995fa4d1ff968a)
- Fixed core queue minimum priority checking code [`e0300f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0300f1415a0d6fbc4c364de4a291feb30ec5eb0)
- Changed queue interval timers from 5s to 1s [`d3106ff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d3106ffad3b097f85df1739be0256a2d1f1ad26c)
- Fixed core queue minimum priority checking code [`1d630dc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1d630dc8c585fe97db254a1a9e3ec50e43a1b9cb)
- Fixed core queue minimum priority checking code [`dc6f6d2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dc6f6d2bc92eab72421662584d2fc09bf6200986)
- Updated to version 8.1.2 [`3942052`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/394205291912b37c924d7c1004bf6a28d0cb713a)
- Removed version check from web gui footer mako code [`5772348`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5772348f3093ae12d2c94339da20e1c6751844fb)
#### [v8.1.1](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.1.0...v8.1.1)
> 9 September 2016
- Fixed core queue code issues related to adding of shows [`e0a1420`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0a1420dce12d1e2b2821524005c8d5bfa59b404)
#### [v8.1.0](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.0.11...v8.1.0)
> 8 September 2016
- Fixed several issues relating to NZB/Newznab providers and searches [`a04f1d9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a04f1d963146344e4373c4352d73246f35fa0280)
- Fixed several issues relating to NZB/Newznab providers and searches [`2d06621`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2d0662158d179caf9414c90d914b2a39dcc5d2ba)
- Cleaned up search code. [`3f513cf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3f513cf2026f0d4ac214505b6f0d5682acb726eb)
- Fixed issues with getting overall size of search results. [`cd19664`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cd196648c2bdc7f84ce52a29906baea3d4111650)
- Fixed issues with core queue code [`321616e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/321616e8ab4bf4a18e50e1ebfa27a6a10801c5eb)
- Fixed code in queue's for handling currentItem [`a2e97e8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a2e97e8769e41c0770a82955fc3ca8db902856b4)
- Fixed code in queue's for handling currentItem [`06f398c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/06f398caa431046672bf2168e5ce2a99a44202ad)
- Fixed code in queue's for handling currentItem [`3663dd7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3663dd786d87368c2a6bc3ab7f3d6642ec6972b3)
- Fixed code in queue's for handling currentItem [`3904a3c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3904a3c25e77b4d8f037a142105048906fdc1e66)
- Fixed code in queue's for handling currentItem [`dfa5e99`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dfa5e99b45e7c2690f0d2882b9515cd05be5d337)
- Disabled raising exceptions for getting file sizes during provider searches [`5494ed7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5494ed7125d16edcdefee8d4235db0c8db2b7442)
- Updated auto-install of requirements to use '--user' flag [`c04c0a7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c04c0a7685518e0e762bb9d131f31f25da14efee)
- Fixed code in queue's for handling currentItem [`6ea6a06`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6ea6a06df01eb65b3f83effe7a698e723b7f69cf)
- Fixed code in queue's for handling currentItem [`577c75a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/577c75a9e59f3ad43402abf707f1eaac7c30f3f0)
- Updated version to 8.1.0 [`4ded8bb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4ded8bb64209b21e416ecf934b401ccebc5a0307)
#### [v8.0.11](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.0.9...v8.0.11)
> 28 August 2016
- Fixed issues with NZB searches and params [`e2793c2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e2793c21c02680034ecebb5f6ee82fd630d31a51)
- Updated version to 8.0.11 [`dbf8ac3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dbf8ac346580f62ee6f0dbb06cc3b531d4f539ff)
#### [v8.0.9](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.0.8...v8.0.9)
> 27 August 2016
- Corrected fixing of unaired statuses on startup [`dd2394b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dd2394b4a0e0473e61057ba952b21437b2abe3e3)
- Updated to version 8.0.9 [`9809565`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/980956586ef6b4851da85c36dc1a22d276985287)
#### [v8.0.8](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.0.7...v8.0.8)
> 27 August 2016
- Updated Regexes. [`cb62854`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cb6285490afae229981f2b2ad4dec56310f72984)
- Corrected session exception handler code. [`aa02f47`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aa02f47f9565881f56fdc47194f8796cb9772f62)
- Fixed some issues with formatting of error messages [`ed27f96`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ed27f96c732b99674ac291e9289ced1e27c2fc6f)
- Fixed issues with NZB providers and retrieving categories [`11e2e41`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/11e2e41fdb46f2710cd38f0eee385c48b3b04dda)
- Version updated to 8.0.8 [`10acd0e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/10acd0e46702834baa9c4bc01341a7010801f74a)
- Fixed issue with mainDB code for fixing unaired statuses on episodes. [`9fa8f46`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9fa8f46677396d9c1749a47c3433a94b8d2bd76b)
- Fixed issue with mainDB code for fixing unaired statuses on episodes. [`b96c56b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b96c56bb1be5090bf4228c94b160b538ca21e22a)
- Fixed issue with mainDB code for fixing unaired statuses on episodes. [`22d9c40`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22d9c404fff2825423c75227ee7dce74af8dc5e9)
- Using error instead of exception for session wrapper [`f4d6cd0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f4d6cd05051efa807bb013bcdf29e05147a61530)
- Updated regexes file encoding [`bb5489d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bb5489d2c61cb31de16631b45c5dbc6f997493ef)
#### [v8.0.7](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.0.6...v8.0.7)
> 15 August 2016
- FIXED: Corrected search url for kickass torrents [`a65d191`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a65d191c24ab789b81dd0fced2de04a0c8080784)
- FIXED: Corrected search url for kickass torrents [`0037fd9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0037fd900c967859ae61a31a5530833dfa253e3b)
#### [v8.0.6](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.0.4...v8.0.6)
> 27 July 2016
- FIXED: Language selector for add new shows page [`a6a399a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a6a399a0cea41238942c49193600ebd82e487274)
- FIXED: Placement of dropdown boxes on home page for listing shows centered properly [`55ce7cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/55ce7cb29da4d9f6bd0253274d73dbaa2dd11738)
- FIXED: Outlines around jquery tab panels removed [`d2669af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d2669afe4eac0e93d75c5cfaaaabc51e629e60c5)
- FIXED: Requirement issues with setup.py when using git links [`80f7ca7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/80f7ca7a40d2a720cf16a8ecc006dfbe25c82040)
- FIXED: Displaying/Editing shows with missing or invalid show directories is now possible [`13dc799`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/13dc7994c20355c456b3d44d0ea7a3bd119dc76b)
- FIXED: Removed border around ui widgets [`2fc2d22`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2fc2d229eed499526a946775a0da68317c6eb7fc)
- FIXED: Placement of dropdown boxes on home page for listing shows centered properly [`4f1d53e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4f1d53e14cc39f22e91e374bb391e76c0ae74168)
- FIXED: References to old code changed to reflect new code, handling of provider urls [`d3044d3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d3044d3e282a315ae54628efc41eac75fc19c5c0)
- FIXED: Placement of dropdown boxes on home page for listing shows centered properly [`a249f72`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a249f72f83ee171ed2611a1ef73c9472daf5035a)
- FIXED: Issue with displaying episode location in display_show template [`824464f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/824464f5223c1524b5243388fc5a25098477646c)
#### [v8.0.4](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.0.3...v8.0.4)
> 3 July 2016
- FIXED: Config file argument when passed in is now checked to be absolute or not and corrected accordingly [`e06dee3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e06dee3efa239c7efbf86fed52b62be1b4603bef)
#### [v8.0.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v8.0.0...v8.0.3)
> 30 June 2016
- FIXED: Requirements slimmed down and replaced python-fanart with updated version using newer requests [`099e0ad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/099e0ad08d621f434af836cbd80493bfb643b825)
- FIXED: Issues with daemonizing and unicode resolved. [`9f53481`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9f5348184c5e85f7f18a56e2a1c7ba6f2c41f3cb)
- FIXED: Issues with daemonizing and unicode resolved. [`ecb16e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ecb16e12c2a028eb2cca3f4c5242fb3c1e0e1658)
### [v8.0.0](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/7.0.22...v8.0.0)
> 20 June 2016
- Fixed issue with anon_url whereby if the URI began with https:// it ... [`#3264`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3264)
- Restruct of javascript routines and imports. [`cb6ecf1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cb6ecf1c5a0594306d554fd45445be03ba1a3e25)
- Fixed WebUI issues with threads being blocked when heavy tasks are executed in the background. [`ce1e345`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ce1e3459dc5c344476050fb7cf845c3ef5492e06)
- Misc fixes for anidb connection code, removed setup function from helpers. [`2a5dfad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2a5dfadefe47d16b794b7d14cef451e14f57dc93)
- Provider settings are now pickled. [`11011b5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/11011b56cc43e1ab4685d807157d0809c8d2d763)
- Fixed file browser js code. [`715ae67`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/715ae678ab3090947b842d2d9c21e43864b5d93d)
- Misc small fixes for provider classes. [`f33bc7a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f33bc7abfc3e612b32786a63d6256558a31f208c)
- Fixed issue with git mako code template. [`13f9245`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/13f9245f4c08efd1dd2fa183b5db47e59bb9bd69)
- Fixed add new shows js code and mako templates [`8fc3fea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8fc3feae2111a1429ae744cfa4da25cf45f7794d)
- FIX: Corrected minor issues with backup and restore of config/db files for app when porting backups from other forks [`57240f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/57240f690271097b228cc8f83b0d4ff0918a7d5c)
- Converted all "from datetime" imports to relevant imports. [`c1879b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c1879b30662cf462f47271f0f84b8b598f5ccbf9)
- FIXED: Disabled same-thread checks for databases to fix issues with more then one thread opening the database files [`6c82baf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6c82bafdeb31994b60e4a5ac66aea48cf16f4f30)
- Fixed issue with ioloop exception caused by sleeping being called from different thread then main. [`0d52dc9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0d52dc9f78da321e3adbb27767078e8ad8f9eddd)
- Fixed issues with custom requests session class code to properly handle kwargs and updating of them when required. [`34a558a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/34a558a29041d36394093e44109ec2154f0d4901)
- Misc WebUI changes. [`f4b88ac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f4b88ac18e2929847eb1642ae1a73c503d0e450b)
- Moved WebUI notification queue instance to core instance. [`eef41d3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eef41d3ea42a3d93a9d585f4154c9e219eaa6c79)
- Fixed responsive mobile layout. [`4ca63b4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4ca63b461704b7f835d837ef75bc79fefdc609aa)
- Fixed issues with git branch checkouts. [`22911d3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22911d3a7f222c4797c4f4b9d6b77437ae305e86)
- Update git ignores [`c3536f3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c3536f3ee296a9df265d50384f8e8accc0a8333b)
- Updated WebUI via Grunt [`e74e982`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e74e98274c7f779eb8be3b51950cb8ba9d8d33a8)
- FIXED: Expand/Collaspe button for episode status manager [`b5caac0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b5caac04de59eb182384cc6bbc5722e0e42fc65a)
- Corrected code issues with new indexer persistent show cache, works now! [`b053953`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b053953308a6c4c9a06515ff3fec5a7d93741bb1)
- Grunt updates. [`4cadf49`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4cadf4956646c08fa68b4cf23324652bd35659a0)
- FIX: Updated web site url [`3e4a7ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3e4a7caa83c28b5ba00e76ab484c8e7d88578b08)
- Improved updater checker code. [`89180e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/89180e252671db58b709b07d9f13de5f51bda1dd)
- FIXED: Detects VirtualEnv properly during pip and requirements installations [`580b217`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/580b217c1f58cb7f836369540611c390abc86edc)
- FIXED: Detects VirtualEnv properly during pip and requirements installations [`5bf6fc9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5bf6fc9849cc06516c1c6199dcb2fa060b711581)
- Fixed issues with show updates/refreshes both auto and forced, enforced to skip grabbing info from DB to ensure new data takes properly and repairs damaged shows/episodes. [`4239c9e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4239c9e9a43f9dfe6a036d3da9e1f78d41187849)
- Update web views code for restarting, added 5 sec timer for restarts. [`1a428b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1a428b29a9b446060f9e8d53dc1d3fb2ad8e3586)
- Fixed issue with stale pidfiles, checks if proc exists then removes from filesystem. [`9005b83`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9005b83841913cdd14d921919971730cba5da85b)
- FIXED: Email notification erros [`8cae227`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8cae227ffc548c24bcb393d4a0735414652837a2)
- Converted all "from datetime" imports to relevant imports. [`cb52ac7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cb52ac7ebf778a07b820d61449ee3f583de0b6e9)
- Fixed incorrect refences to srConfig class in mako templates. [`3edf3b8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3edf3b861ec1781bdf4d52accc4e395b6842c888)
- FIXED: When disabling torrent or nzb functionality for searches but not disabling individual providers under those categories the non-disabled providers were still being used for searches even if the main classification of them was disabled [`6fd10db`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6fd10dbb1e1de352492f6b71cbfccb3591f52fb0)
- Updated bower requirements and core js code. [`a4f17c3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4f17c30244ec02f3fb9744da988497cfb3209cc)
- Changed code for pip installation of requirements. [`bce2784`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bce2784751d921eb5fddcb7bf899017d08a155e5)
- Fixed several code issues relating to restarts of sickrage app. [`db8e33c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/db8e33cf595cfb442cffd4d45d66530712c05e98)
- More responsive-ui fixes applied [`9bd21fc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9bd21fcfd6fcb0d4c90355fd5328053ab101389f)
- Updated readme [`4e28dee`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4e28dee8f40513b437f0143171608a7472a060fd)
- Updated repo readme file [`4b81746`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4b817462810348c8cb93647c4218f264b41855f7)
- Updated repo readme file [`a81b7cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a81b7cb29e6e25b88624fdf9cb0bd2f62107c789)
- FIXED: Requests exceptional handler can optionally be turned off to allow custom handling of certain exceptions [`d293d32`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d293d32347408d01b8fbc629ba62a899591da30b)
- Grunt updates to core js files. [`358bd5c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/358bd5c3770033b79c1d9fe218c7520f2d8713ce)
- FIXED: Queue was not properly looping through tasks, corrected by adding a while statement [`13b9977`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/13b9977bd053f935e260e830acfbd590a9d86364)
- Fixed issue with daemonizing app to background on linux. [`6bbb744`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6bbb744a5150a16ec425ac6eb9dabb76def9a96a)
- FIXED: Daily searches now set shows airing on the day of the performed search to wanted instead of including hours and mintues as a deciding factor [`c46fbc6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c46fbc67dd7ecb7a457f01fa6d0b03461f3fd16d)
- FIXED: General settings during save was missing new stale shows variable causing settings not to be saved. [`9418082`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9418082e7a6b23edb273476c6537af4c67f480a9)
- FIXED: Issue with new pip upgrades and requirements installations [`0a6a028`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a6a02882a03116262617a0a924773af2581d7d7)
- FIXED: Queue was to slow with previous shutdown implementation so added a new improved stop event [`082c883`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/082c8830e7a7bc43e07d1ebb0f0eb1343044eddd)
- Fixed issues with sys.stdout during installation of requirements. [`d5b3d69`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d5b3d69a63fcd2806a6a2e8a559fa6822cc43816)
- Fixed issue with auto-detecting git executable path. [`15f2dd5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15f2dd5f8c6b6c3befc816533cc3e9d1fcf01a57)
- Fixed several small issues in version updater class. [`df6068f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/df6068fb808f11aaed000eb1df62c812e0613870)
- Updated changelog [`ef60c54`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ef60c54ebeb8db4f9e3f872670ddba57ea93360c)
- Misc fixes for version updater [`ee11333`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ee11333d3bcaf260a653fb59b10859936a70cf0d)
- FIXED: References to sleep in some modules where incorrectly specified [`ba14b9d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ba14b9d673d25f59b7f1bb212fc192ab6057a3df)
- Fixed issue with version updater not properly determining install type. [`85fe032`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/85fe03227f17e70a83f8f4784bb2affea5e3ab2d)
- Fixed redundant loading of network timezone data from database. [`0d2e6e0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0d2e6e07599f67b64fc159525565104cdc83981e)
- Updated name cache to re-load saved data from database and save to database on successful builds. [`3de2a0e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3de2a0edca8b0a69d91a75d633aad3de3d103e9b)
- Updated name cache to save show to db when building internal cache. [`8845cff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8845cff7c7354d75d2ef094533199db12e73c217)
- More updates made to version checker [`7b8d27b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b8d27b8154398b67b91ba9b9014f1b2e6164607)
- Updated resources for checking if pid exists. [`0848dd4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0848dd4a0d71be882d78251535059b55934d9153)
- Removed gitlab-ci runner config, moved to pages branch [`9fdf493`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9fdf4939dce1a3233b6a624443f5ab16b704b8fe)
- Corrected exception messaging handling for refreshing shows from folders. [`28641dc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/28641dc1a776ac7042a12513eec5589dcb092907)
- FIXED: Requirements installation now recursive [`f1919a1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f1919a1cf65bb67c1cb7f8119dd9bd2b72f46516)
- Fixed more issues with git mako code template. [`5f896e3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5f896e3e12b2b8175fd2015687c9b8301cfd7aa5)
- Fixed issue with anon_url whereby if the URI began with https:// it added [`e83d29a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e83d29a05d8bcfc47fbf2205162c11202733c66e)
- Corrected standard_absolute regex [`2b3eb60`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2b3eb6051aa06cec298fce45ef6b4dafb55b0d78)
- Fixed several issues with database operations including upgrading of database versions. [`f5a81d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f5a81d70f762ca4da4da2e1febfb1b496ce5bfc9)
- Fixed str type error in version updater. [`4c00838`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4c00838603122dc55228e875f0f7fdadc08145b2)
- FIXED: Removed PyDrive from requirements and constraints files, using custom internal methods instead [`a8568d4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a8568d4e8f5e7e81175da7c0e22ba8c693fa3125)
- FIXED: Incorrect filename specified for constraints if performing a install via setup.py [`e7e7340`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e7e73406f3ef5fc2a8369d155a1af370e9b4f6f7)
- Updated pip manifest. [`1508342`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1508342fb2177410e24e581a7351188ce88526a3)
- Removed "publish" cmd from setup.py [`04059de`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/04059decb695af946e0e0123ef3815a01d7fd871)
- FIX: Corrected issue with email notifier and unicoded username/passwords [`9b07c19`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9b07c19917bb51961dd1d911b909023e97cae1c3)
- FIXED: Web client exception handling now logs via exception not error [`fa6a00d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fa6a00dc3056a5bac9516cd24714609137a98f23)
- Fixed a type error issue in version updater. [`690343c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/690343cd1d521ea3896ebbe6f6c67ca6c171d71c)
- FIXED: Issue with shutdowns and queues resolved. [`553cd75`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/553cd75d76074824de0a9355f47126723c528267)
- Fixed issue with snatching torrent magnet links. [`1866bfa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1866bfa7b99063d96e9eb1c48ca3d3324e0371f5)
- Updated readme.md [`8aa69f5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8aa69f54989ad9b469f14f0c6f397c833196d433)
- Updated donation link in templates. [`f73c439`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f73c439dcb47e6ca69a80dd3f73648187efcb0a0)
- Updated setup.cfg [`782dd7c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/782dd7c6fba3312eafb2e29de5118e868ea09d4e)
- Fixed issue with transmission torrent client ratio feature, confirms ratio is a integer or long. [`24224c2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/24224c213b59c21a185d3dbd456b7fe3705ad1ec)
- updated permissions [`c76c77b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c76c77b518465ec1ed8cd19fc4364d035fd19ef3)
- Updated permissions, set executable bit [`e97d758`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e97d7582e600eb369224e8718592524ca25ffb10)
- Restruct of javascript routines and imports. [`504865f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/504865fe4546e3b45ff48b7d899ddec91ef1a5de)
#### [7.0.22](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/7.0.21...7.0.22)
> 8 February 2016
- Fixed issues with running as a daemon, moved logging calls to start after daemonizing. [`a58ca53`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a58ca539dd9864ffaafcca5dcb037cd408988aca)
#### [7.0.21](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/7.0.18...7.0.21)
> 8 February 2016
#### [7.0.18](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/7.0.17...7.0.18)
> 8 February 2016
- Replaced IMDBPy with imdbpie to avoid requirement of lxml. [`9e1c098`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e1c09809626a84ddfc1d1dd1ebe15012923eb09)
#### [7.0.17](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/7.0.16...7.0.17)
> 8 February 2016
- Removed requirements module and moved code into main module for startup. [`146ad83`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/146ad834956b386573cb63d3af405775a3296eeb)
#### [7.0.16](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/7.0.12...7.0.16)
> 7 February 2016
#### [7.0.12](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/7.0.10...7.0.12)
> 7 February 2016
- Reverted all tornado gen.sleep calls to time.sleep calls. [`f352ff9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f352ff901417dcfcbda79fa9fc774f1e4680ddc1)
#### [7.0.10](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/7.0.5...7.0.10)
> 7 February 2016
- Reverted database back to using concurrent futures for multithreading. [`db8ad5b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/db8ad5b2e20b70f91ff6eb8dcfe138c29e543be2)
#### [7.0.5](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/7.0.3...7.0.5)
> 6 February 2016
- Changed database queries and upserts to use multithreading correctly so to not block the web-ui. [`fd1f005`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fd1f005ae7dd5898503aeaacbe31fc25c81a122f)
#### [7.0.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/7.0.2...7.0.3)
> 6 February 2016
- Moved a few constants to the top-level of main module. [`5adef32`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5adef324e68b82ea4b10ac4ad629ce3171b9cea2)
#### [7.0.2](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/7.0.0...7.0.2)
> 6 February 2016
- Fixed issues viewing schedules regarding datetime problems. [`832840a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/832840ae06c0220cb3b377ccbb2237137d1bc392)
### [7.0.0](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/6.0.59...7.0.0)
> 6 February 2016
- Release version 7.0.0 [`a6e82cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a6e82cb66e71309ccef6ce9edbc194f68c4b8ad1)
#### [6.0.59](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/6.0.58...6.0.59)
> 6 February 2016
#### [6.0.58](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/6.0.57...6.0.58)
> 6 February 2016
- New daemonizing code added [`1edbb2a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1edbb2a2293fd50b2ce496602c5ceec3190c3d66)
#### [6.0.57](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/6.0.56...6.0.57)
> 6 February 2016
- Corrected issues with daemonizing sickrage on startup [`e00e5f0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e00e5f054c9131c1d79cf6525072eb687ea04ed7)
#### [6.0.56](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/6.0.55...6.0.56)
> 6 February 2016
- Fixed more issues found with startup and pip installs/upgrades of required packages when running as a non-root/admin user [`13be08c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/13be08cfb6ea4f6c985c28326bac83fb3d1ef2c0)
- Fixed issue that was causing logger to duplicate log messages. [`991c4d4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/991c4d44a0a56cf99b313c627147cb630f05c2bf)
- Corrected path issue for tests and travis-cl [`35607d0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/35607d06486c234ec395dbde1c903129d4dfac5a)
- Updated travis-cl run script for tests. [`c5e4a38`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c5e4a38f21b7ddb837c1320a9d44da432b776582)
- Version bump to 6.0.56 [`9f8f618`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9f8f618f1066a7d6964ac94c6198f04e75999f52)
#### [6.0.55](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/6.0.52...6.0.55)
> 5 February 2016
#### [6.0.52](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/6.0.50...6.0.52)
> 5 February 2016
#### [6.0.50](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/6.0.45...6.0.50)
> 5 February 2016
- Fixed issues with pip updates on startup. [`23a7f73`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/23a7f73e6cf076b070f2ec91d55071e04c4ee5a7)
#### [6.0.45](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/6.0.30...6.0.45)
> 3 February 2016
- Restructured folder layout to conform to pip install standards and fix startup issues. [`7c4d0f0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7c4d0f0889cac1f41c02a3b3e64c12875c4fa64b)
- Fixed issues with installed/upgraded packages not being detected properly and re-installed anyways. [`dbb0550`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dbb05507bfab8b63872029ab9c961ad25072c02d)
- Fixed module import error on startup files. [`7a522f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7a522f1d47ec309caf81ac586865997afcc6e8a2)
#### [6.0.30](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/6.0.27...6.0.30)
> 19 January 2016
- Pip installs now use Install class for installs/upgrades during startup, this fixes more startup related issues. [`3ae3625`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3ae36256459a8468e6847e2ca2a071cb3753516b)
- Fixed issues with setup.py for pip installs. [`38df002`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/38df0020156a2b188c0649a042dd721e21060301)
- Fixed issue with thread naming and instances not being classes [`de05f45`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/de05f45971fc86f3f5dfbeb625cbe16c4b72cf71)
- Bump to version v6.0.29 [`f49d861`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f49d8613cdfa4e36b44836877a79380dfeeada5f)
- Bumped version to v6.0.28 [`19c425a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/19c425a5b858e326ae671b8fdfc330d7c9b25e6e)
#### [6.0.27](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/6.0.25...6.0.27)
> 18 January 2016
- Fixed beautifulsoup issues with html5lib and parser, resolves several issues in relation to torrent providers [`22a357a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22a357a68354f89463b7becbbb980d25b8f342ba)
- Fixed startup issue related to pip installs [`b6ab8a3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b6ab8a3e198600dd503c05332aaae9a0ebdcc79f)
- Fixed 2 more bs4 issues [`57149b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/57149b30f249d2d44e569556cae8660a3270fcf9)
- Fixed issue with privs checker at startup [`015e69f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/015e69ffecfc94059b1fd5f04cc36d789b17a9f3)
- Correct path mistake for travis-ci builds. [`ededc5f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ededc5fa43233e3b80ba7737397ef0d8320d5cf6)
- Bumped version to v6.0.26 [`22bb3b6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22bb3b63ba8a8e4a5a5ab0bb8721c2dc6d17c15b)
- Need more coffee [`f75ba3f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f75ba3f97b2f1404a7b9ff272ef5435b05d85ede)
- Changed executable bit on install.sh [`d2cc69a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d2cc69aa62872797ef829354fe92b3f8cca2ae3c)
#### [6.0.25](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/6.0.24...6.0.25)
> 18 January 2016
- Changed executable bit on install.sh [`0bed0df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0bed0dfd9ed0763ce8ec0a1f918c1d0ff78ba237)
#### [6.0.24](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/6.0.23...6.0.24)
> 18 January 2016
- Fixed database call issues for daily searches [`2a73bc9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2a73bc99e9818156d039e6dbb853409f577e99c6)
- Updated travis-ci tests to install requirements via pip before performing tests. [`fdef5c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fdef5c782d00e46bde2a593539e2c00e4967289a)
- Fixed issue with pip installs being unable to locate get-pip.py [`8d71dbb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8d71dbb25c2030f28472b544a0e7e2e530e5a5cb)
- Fixed issues with status view [`b911bf7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b911bf796731cec83aa2fdf24dc54a20d5907831)
- Fixed issues with detailed history views [`e2067d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e2067d71b1edfbae630ab162dd22ef2408e9f926)
#### [6.0.23](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/6.0.22...6.0.23)
> 18 January 2016
- Version bumped to v6.0.23 [`ef7facd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ef7facd5aae34565b54645aec60fd3ef5d19d942)
### [6.0.22](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/4.2.5...6.0.22)
> 18 January 2016
- NEW: Rewrote the startup/restat/shutdown of the app to utilize tornado's ioloop and autoreload features. [`f1f73a4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f1f73a40c9ef5f79a58092ca2a2ef0d4789d80fc)
- Complete restructuring of modules and code and changed all sickbeard references to sickrage [`0be25da`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0be25da39ae5a7cfc41af43e3c046b9bdc1a7a7f)
- Complete restructuring of modules and code and changed all sickbeard references to sickrage [`3fd9dbd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3fd9dbd708500776bb055ab1cbf7a36e72cfb368)
- Fixed all unresolved references to imports. [`c36f208`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c36f208c13384c80ecfd634f9dc3b3b154a68da9)
- NEW: Rewrote the startup/restat/shutdown of the app to utilize tornado's ioloop and autoreload features. [`c0892e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c0892e4d1241d66ba07d84a298fcca2aa744157f)
- Updated to version 6.0.0, restructing completed. [`3238b91`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3238b91ae43afe1b0c8496d81d25720b84239187)
- Updated templates [`ac85744`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ac85744fbf4c5d111c3521588f04de13bae5535b)
- Fixed more unresolved references to imports and more issues revolving around naming of episodes and setting of qualities. [`e74d2c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e74d2c4c7e8b49eb34bea6edbefc4eea9d900a23)
- Further fixes for restart/shutown of app. [`9a8d283`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9a8d28302c655ab0a5edff9669a9dfde2605fc75)
- FIX: Corrected several cyclic depends. [`f8621be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f8621bea39d8333d4713a9386363196967daa103)
- Fixed startup issues related to patching of ssl sni contexts for pip install of required library files. [`7c81090`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7c810905087c8ecde0896fe9787c42ea6115d551)
- FIX: Corrected DB code to handle list instances when performing fetchall and fetchone. [`8237e9f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8237e9f085567eddd30016e9c326a71bded9c76e)
- Fixed timezone issue for windows users causing a mako exception. [`b60ad73`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b60ad73096d1f4eea855f896b124625ec616cf2f)
- FIX: Corrected status web view [`4ee4a0f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4ee4a0fe8445a3c566122c35121dd7b6d4b893b3)
- Fixed several bugs with sql database calls and connectors. [`0107af8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0107af88d9f18e881e17204af52b567cd398a395)
- Fixed startup to automatically install and upgrade pip to latest version. [`f4a2533`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f4a2533e346c0513536acb93e8fcb79c74ed4592)
- Fixed issue with queues by switching from apscheduler to ioloop events, [`e538324`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e5383241bf793dc813026e2d87a9c6336ef7de14)
- FIX: Corrected several more bugs in notifiers including plex [`4a62a6f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4a62a6f0183e9def35e722ec444c566da6924b37)
- Fixed startup issues relating to version checks [`3005b23`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3005b23670fe9ab622b0e59f7e249fde5ef4a1e5)
- Updated init scripts. [`94d6d35`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/94d6d3514dab0cbb10f2f9a80ea79a1c67f0a05e)
- FIX: Corrected DB code to handle list instances when performing fetchall and fetchone. [`853668b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/853668b5c10c70b441aaca580644ce2ad19a364e)
- FIX: removed logger calls that were to early in the code [`ad6f7ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ad6f7ba9f46fb995f5f045860e797d8ae7cee9e1)
- Complete restructuring of modules and code and changed all sickbeard references to sickrage [`b4c4aad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b4c4aad68f12660fb7c70cc83c985f173d834adb)
- Fixed class naming issue between validator and tv classes [`6bf50fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6bf50fea7d32b726d7efd192dda060a5507529c6)
- Updated git ignore file [`505022f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/505022f75d9cb89bdad2c4400b160e5f73da93b8)
- Fixed paths for requirements [`bda28a2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bda28a2a7f8d55b865099378ed095c1ca8cb7800)
- Version bump to v6.0.3 [`747734e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/747734ec7f10164084346004921f66d3a2e9d4f9)
- FIX: Bug in login template corrected. [`234ec95`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/234ec959e6cf6a079ca2b1b4478588c532774b63)
- FIX: Made lxml a optional requirement [`0957c98`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0957c987cf6a80ab55093def6a92651780e78523)
- Fixed issue with adding shows and quality presets [`c2cb8e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c2cb8e1648072554038c4a3017b8081cd064fc0c)
- Fixed setup.cfg [`3c89ae4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c89ae45b50923acdbb75dc932aa21d344a9efba)
- Corrected a startup issue with installation/upgrade of pip [`d3761be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d3761be201c03e8c54f53ae63135cfed70ac7ca2)
- FIX: Corrected namecache freq [`b583a6e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b583a6ebe2c33b8f7696594605958d7cf88db6b7)
- FIX: synoindex_notifier code correction that was preventing post-processing from working [`67e09f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/67e09f63ac3071438a05209892ef8a21d75d0e3f)
- FIX: Corrected logfile name for tests. [`eac348d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eac348dc35271d7c6c50db9d8614d9284a3167c5)
- FIX: Corrected provider result bug [`1c39d11`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c39d11b058f329c16c4a909f900d15404a1eaf5)
- FIX: Corrected issue in requirements.txt file [`ee97067`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ee97067af22dda3fc5a97fbec3b85262de372e78)
- FIX: Fixed issue with parsing air-by-date shows and displaying results. [`ef72b4e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ef72b4e916f45205eaade0bc4cfedd2df0601db5)
- FIX: Missing import in common [`b19e4d1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b19e4d1b41228ad0b293bf08015cfae100bf6fd6)
- FIX: Corrected missing seedratio attribute for provider results [`0b201a9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0b201a9d5b725c69e7cea17c41a662949cd601bc)
- Fixed issues with removing a show via mass edit when show variable is None [`279374c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/279374cc9eb47aa239d1861a1906d1f857295595)
- Version bump to v6.0.22 [`0ad39f2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0ad39f2500819cf78cb896c206f6a72b719ec119)
- Version bump to v6.0.13 [`e0333fc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0333fc7e5be3b898ffdf810f6166bad3905fe1d)
- Fixed issues with history view [`ece5ec8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ece5ec88a5e9badaf182354d59ca9cb522246de1)
- Fixed date issues with scheduler [`9567b1c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9567b1c21be2480dbb0a1250dc1218e94a8699a7)
- Version bump to v6.0.12 [`cca222e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cca222efa24266c20b11f0dd8419a52758b003c2)
- Version bump to v6.0.5 [`d75b834`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d75b834af1aa131bf21a6efcdc133f540c74f583)
- Version bump to v6.0.4 [`45b38cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/45b38cb0f372fb76aee7cca7ba9d9cc92c0911de)
- Fixed requirements file [`22693cc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22693cc1f62649b903419c6b8b4354acd87d46ea)
- Fixed restart issues [`168db6b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/168db6bee18f3efdaad30049e907e87f9ffedb7d)
- Rename History.py to history.py [`f589e49`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f589e4907ab438312b41cf56348ab72db516ec99)
- FIXED: permissions on init scripts [`6bd2f45`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6bd2f45646b4444c657fcbbd252343894c285ece)
- FIX: permissions on main executables. [`dac5b49`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dac5b49a53063fcce487d3faea1c7d379df14d6d)
- FIX: Corrected path for requirements.txt [`76d19ed`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/76d19ed1f272482fbe8c508fdfc37b6f42b02842)
#### [4.2.5](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/4.2.4...4.2.5)
> 22 December 2015
#### [4.2.4](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/4.2.3...4.2.4)
> 22 December 2015
#### [4.2.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/4.2.2...4.2.3)
> 22 December 2015
#### [4.2.2](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/4.2.1...4.2.2)
> 20 December 2015
#### [4.2.1](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/4.2.0...4.2.1)
> 20 December 2015
#### [4.2.0](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.1.0...4.2.0)
> 20 December 2015
- Removed nxtgn provider [`#3203`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3203)
- Add RSS to Strike [`#3191`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3191)
- Fix readme.md warning typo on develop branch [`#3193`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3193)
- Added autocapitalize="off" to login form and text fields throughout c… [`#3196`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3196)
- Add RSS to BTDigg [`#3186`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3186)
- Save multiple plex servers [`#3184`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3184)
- fix bluetiger auth [`#3185`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3185)
- update user information on anime Black- and Whitelisting behaviour [`#3172`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3172)
- Remove FTDB provider [`#3174`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3174)
- Fix post processing non-ascii [`#3176`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3176)
- Use login on initial Github request if defined. [`#3175`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3175)
- Add real to proper strings [`#3171`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3171)
- Encode long type as int [`#3164`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3164)
- Fixes extra scripts for subtitles [`#3163`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3163)
- Added DVD parsing for %SQN, making sure group is not included in parsing [`#3159`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3159)
- Use names parameters when adding a show from the API [`#3153`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3153)
- Update parser.py for PEPs 8 and 263 [`#3148`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3148)
- Update regexes.py for PEPs 8 and 263 [`#3147`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3147)
- Update tivo.py for PEPs 8 and 263 [`#3145`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3145)
- Update wdtv.py for PEP 263 [`#3144`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3144)
- Update kodi_12plus.py for PEPs 8 and 263 [`#3143`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3143)
- Update mede8er.py for PEPs 8 and 263 [`#3142`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3142)
- Update mediabrowser.py for PEPs 8 and 263 [`#3141`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3141)
- PEP 263: Add encoding declaration to kodi.py [`#3140`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3140)
- Update metadata/__init__.py for PEPs 8 and 263 [`#3139`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3139)
- Update generic.py for PEPs 8 and 263 and remove unreachable code [`#3138`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3138)
- Update helpers.py for PEPs 8 and 263 [`#3137`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3137)
- Update ps3.py for PEP 263 [`#3136`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3136)
- Update indexers_config.py for PEPs 203 and 263 [`#3132`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3132)
- PEP 8: Move module level imports to top of file in indexers_exceptions.py [`#3131`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3131)
- PEP 263: Add encoding declaration to indexers_api.py [`#3130`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3130)
- PEP 263: Add encoding declaration to indexers/__init__.py [`#3129`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3129)
- Update maindb.py for PEPs 8, 203 and 263 [`#3124`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3124)
- PEP 263: Add encoding declaration to databases/__init__.py [`#3123`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3123)
- PEP 263: Add encoding declaration to utorrent_client.py [`#3126`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3126)
- Update transmission_client.py for PEPs 203 and 263 [`#3127`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3127)
- PEP 263: Add encoding declaration to failed_db.py [`#3122`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3122)
- Update cache_db.py for PEPs 8 and 263 [`#3121`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3121)
- Update deluged_client.py for PEPs 8 and 263 and streamline conditional [`#3114`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3114)
- Update download_station_client.py for PEPs 8 and 263 [`#3116`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3116)
- Update clients/generic.py for PEPs 8 and 263 [`#3117`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3117)
- Update mlnet_client.py for PEPs 8 and 263 [`#3118`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3118)
- Update rtorrent client for PEPs 8 and 263 [`#3119`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3119)
- Update deulge_client.py for PEPs 8 and 263 [`#3113`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3113)
- Update clients/__init__.py for PEPs 8 and 263 [`#3112`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3112)
- Update tntvillage.py for PEPs 8 and 263 [`#3111`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3111)
- Added MLDonkey basic client [`#3107`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3107)
- Fixes https://github.com/SiCKRAGETV/sickrage-issues/issues/3580 [`#3109`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3109)
- Updated subliminal (develop) to newest version [`#3106`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3106)
- Add missing CF error codes - fix SiCKRAGETV/sickrage-issues/issues/3577 [`#3105`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3105)
- Update webserve.py for PEPs 8, 203, 257 and 263 and streamline dict/list creation [`#3099`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3099)
- Update helpers.py for PEPs 8, 257 and 263 and streamline datetime call [`#3094`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3094)
- Update sickbeard.py for PEPs 8, 263 and streamline datetime call [`#3087`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3087)
- Allow user to submit 'Unknown error code' message [`#3097`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3097)
- add aria-haspopup to force ie11/edge to emulate hover on these elemen… [`#3098`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3098)
- make sure the caret is in the right place on -xs (mobile) layout [`#3096`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3096)
- Update traktChecker.py for PEPs 8, 263 [`#3090`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3090)
- Update blackandwhitelist.py for PEPs 8, 257, and 263 [`#3088`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3088)
- Make "newpct" configs more n00b friendly [`#3067`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3067)
- Import datetime to fix undefined errors with sabnzbd [`#3065`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3065)
- Added support for Calendar Icons in Google Calendar (Develop branch) [`#3064`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3064)
- add category options to nzbget and sabnzb for backlog episodes [`#3056`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3056)
- Fix issue #3491 [`#3049`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3049)
- Only use the exception logger for ERROR level (maybe we should use logger.warn() too xD) [`#3609`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3609)
- Merge pull request #3109 from duramato/patch-6 [`#3580`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3580)
- Dont try normal regexes when we know the show is anime (still might need to flip the order on line 87) [`#2834`](https://github.com/SiCKRAGETV/sickrage-issues/issues/2834) [`#3562`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3562) [`#946`](https://github.com/SiCKRAGETV/sickrage-issues/issues/946)
- Decode the data back to unicode! [`#3527`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3527) [`#3527`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3527)
- Make sure airdates are > 1 (really 693595) in webapi to stop erroring when unaired episodes are asked for info [`#3512`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3512)
- Make sure airdates are > 1 (really 693595) in webapi to stop erroring when unaired episodes are asked for info [`#3512`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3512)
- Use a lookbehind to not match roman numberals if they immediately follow an e [`#3544`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3544)
- Use a lookbehind to not match roman numberals if they immediately follow an e [`#3544`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3544)
- Lint postProcessor [`#3527`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3527)
- Match all torrent_row classes on libertalia, not just new [`#3543`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3543)
- Match all torrent_row classes on libertalia, not just new [`#3543`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3543)
- Remove feedcache, update feedparser [`bda03f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bda03f4af8ff08ccd61697fb07cee137055bbe40)
- FIX: Fixed a bug that was causing anime settings page to detour to subtitles instead [`8384e29`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8384e29ef1f95a36a70a916b1373e92f290d92ba)
- Code changes to correct flow of ascii <-> unicode issues brought in by previous code updates. [`425aa9c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/425aa9c025e157c6ae4bc190735d8c52f938676d)
- lint old *.js && update views [`32bad59`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/32bad593424746caa92489a735b36845e16e8114)
- Fixed bug in db connector, was not closing db after commit. [`64e7572`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/64e75724d48d7e4936b721028e47d5401c73ed63)
- Remove unused lib/futures [`7b289da`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b289dacd04c9247eecfc10e4b08cdfd58310f46)
- PEP8: comments should start with '# ' [`eed6610`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eed661038b390693930974dafc78c44a0864b07c)
- Remove the reload of sys and setdefaultencoding hack that is frowned upon and unpythonic [`99d4707`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/99d4707478e31c11d84dfea6baded9e525499f7c)
- Fixed more unicode decode/encode bugs. [`fcc4fb8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fcc4fb882cf566b96a4f908a72856e26cb73cbe2)
- FIX: Corrected code for log viewer that was preventing proper display of logs and log levels. [`9a0f85e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9a0f85e44aae5895624f4f5997d97d59464ded2e)
- lint new/*.js [`ae5b8b5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ae5b8b5da3dbd8861969c1ce88f42f7d6aaaf03a)
- linted js files [`03a781c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/03a781c52eae9e2fb5f9df23422ce024aed55385)
- Flake sickbeard module, lint clients [`5acef40`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5acef4058934adbd3456dcf9a729fbe72ae3c5e7)
- Fixed unicode handling issues for generatortypes and revamped the encoding module source code. [`f14764e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f14764ef4a6a77baecab46db5ef697633e879605)
- New provider: www.newpct.com [`c220ff2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c220ff2621737b1a472fc173d4ff17ec37024219)
- Hella lint errors and some actual bugs fixed [`9736515`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9736515c72e16854353f6874b4f227b248658812)
- lint js [`29cc94b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/29cc94b08ab36572540ae81f4c7ae344fd3f95dd)
- Clean up metadata providers a bit more. [`5904423`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/590442392c3e657986a187485f7fae3586bbdbf5)
- Remove glype proxy support [`012c0be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/012c0be2b006696afc3b9ad2ba31f77f6a96049a)
- FIX: Converted last of the old-style logging calls to work with new-style logging module code. [`8836404`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8836404571df13fecb365dbc4dd7a9fc705202a7)
- FIXED: Issues relating to restarts from web app corrected. [`1a98807`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1a988072fb7115b85b81e695baf6507bf506c3a4)
- Fixed unicode issues with web views in app. [`f12bfb1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f12bfb1368bd7edb670ea26b412fb103c49067af)
- Linting webapi and fixing a few problems [`7b98cb2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b98cb2897d7113e78ac0284156e75c545c6bc80)
- Fixed unicode issues relating to encoding checks at startup of app. [`ce5f000`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ce5f000721260d3deeb0e418367a2cf11602a0f6)
- Fixed issue caused by nextgen removal. [`2df5dee`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2df5deeaedb4f0c5a3cc490efbb1d7059e6e01b2)
- Corrected issues with shutil_custom imports [`e1645e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e1645e210e14b7fc954b75ebb93b5c96ccfa3835)
- Fixed unicode and logging issues with config module. [`81e7779`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/81e7779094a5e1f19faf72d61353e0340a4f0b6c)
- New feature: User can select episodes and delete them both from show and hard drive. [`ed5d3a1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ed5d3a188e5bc6a3a1139adf42ed01cbb848b6dd)
- Fix up code and build testing [`21c75ee`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/21c75ee53d187b574aef8724aa08f7f684b67e86)
- Fixed bug in shutil patch preventing post-processing from completing. [`f77cdb3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f77cdb3a10de071d2eb353204b56373222fb74b3)
- Converted more os calls to use ek wrapper to prevent unicode issues. [`cde0cfd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cde0cfd78fd1e7417731d1b51ab8452514a72e31)
- FIX: Fixed bugs causing undefines when trying to display or edit a show. [`e9e4d71`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e9e4d71c08dd75c30c580a93270c551f4a19d8de)
- add category options to nzbget and szbnzb for backlog episodes [`fccc3f3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fccc3f3522b5a59a4ead5e1e16f239410ccfe9b9)
- Lint sickbeard/__init__.py [`3c00d3c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c00d3c736015202bb0b08167c397c9655669c2a)
- PEP 8: Fix indentation and add/remove blank lines for consistency [`de1cae3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/de1cae3029cb81c3b5bb34ba6c88425454d77704)
- Fix show download statistics (downloaded, snatched, totals) cache issue [`78fdf42`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/78fdf429c6bdef4771edc8fa1bf5d73dc5dd55dc)
- Fix show download statistics (downloaded, snatched, totals) cache issue [`4f1a13b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4f1a13b3a4c0295aba67b47508515abf9154d3d1)
- PEP 203: Replace dict creation with dict literal [`251493f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/251493f400c458b31033ccd653dc326b6747b374)
- Code changes to support not using feedcache and new feedparser [`4f83679`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4f83679cd0ff6be0ca88a33cc9b502e31e959674)
- Fix displaying non ascii in log/error viewer [`5d53ef9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5d53ef93afe320314fee0eaebe2ecc372d7dd83a)
- Remove proxy setting from r/w of config, and in gui/webserve [`56b7f57`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/56b7f573cc1736fe31e4fd9aff6c053bdf43af0d)
- FIxed bug preventing shutdown signal from being caught correctly. [`99ea156`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/99ea15617bfe34e4585b10adae777a6716747f1f)
- Fixed issue with unicode handling of generator objects, resolves issues for post-processing [`9fd5f8f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9fd5f8f9c4b5caee031d0e76c11e24f93bf5eddc)
- FIXED: Corrected stdin/stdout to properly handle unicode encoding/decoding [`64badf3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/64badf3b10ec1dc770357088d38b3c7b10692ebe)
- Converted shutil calls to use ek [`456bdde`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/456bdde8a0385c16e8363fa085235fb262338e39)
- FIX: Better handling of bozo errors on rss feeds [`4595b79`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4595b79fe116ad9c5e81f80fd52a5387379e1c10)
- Fix setting home layout. Will be more issues popping up now that mako cache is working! [`fea3f1e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fea3f1e21ceba437f2cb0958dadb021485ac9c7d)
- Fix setting home layout. Will be more issues popping up now that mako cache is working! [`3ee22fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3ee22fe9711cd9a4641a49140268ebf18e7cb134)
- PEP 8: Convert tabbedindents to spaces [`4566d2c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4566d2c8eb37d10d17ef36518fb822bf8f7b126d)
- Clean up old tornado location before it is imported [`16f3118`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/16f3118e8338651d1d730d42ff4c052af7a1ecf2)
- PEP 8: Fix indentation and remove excess blank lines [`b0ba95e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0ba95e57d7565badb033c245021e3d95bbbf5a3)
- Re-add womble feed parser test, and make it work [`18056a2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/18056a265f866fc0352761cccd1777e8287985ae)
- add base .jshintrc for js linting [`2984dc5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2984dc51f6d7e1c01187308899cdf2e3576a396f)
- Fix synoindex calls in helpers [`4b352bc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4b352bc44e189f45937b98b0365cc1b9c6d5c7eb)
- Remove "append_identifier" feature introduced with newpct, as it breaks multiple other features such as history, failed download handling, proper finder, removeWords, etc. [`b83170f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b83170f9ccba718df48ab3ba052202895c195169)
- Fix history layout caching issue (cant define mutables inside <%!) [`505ad2a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/505ad2a9326eba0f9f77b08338ef6f4a87243c8d)
- Fixed bug in shutil patch preventing post-processing from completing. [`0496b1f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0496b1f7b3320027e96788de48501dacaa467186)
- Fix unicode in nfo's, clean up some log spam [`b45b3bc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b45b3bcd0f549e931ec1b8a68e4073318662374f)
- Corrected spelling for post-processor class name. [`8b2eeaa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8b2eeaa52263a216949cf615408d67a94736a085)
- linted js [`baa20ef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/baa20ef23b6e2a8190dc0c50833c4224c316c907)
- PEP 8: Convert membership test from 'not x in y' to 'x not in y' [`d7202f5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d7202f554a9fe0b32e190d2f9d7f057b7e479bc4)
- Further unicode issues corrected regarding post-processing [`7ce84f5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7ce84f51f1b184eb7460448a47ea17a2e31ded27)
- Deleted _get_episode_search strings [`3c25f0a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c25f0aee885e42c6e5872fc53f492ac9d26da15)
- Fix bug when opening the postprocessing config [`0d27120`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0d27120235460cff0f7979e1fee3b3fdcbb79c94)
- PEP 8: Refactor variables that shadow built-in names [`0111c52`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0111c52efc360613d16b4b11bb35f3c876ab6e96)
- Minor code correction for github api [`2d8c058`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2d8c0588532d924af5807938a000529cfb07cfea)
- Fixed copy/move functions to not remove the source file if a error occures [`2022dce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2022dce0b6a3afaf7de7533e78bbf36b07e08b13)
- Fixed bug in shutil patch preventing post-processing from completing. [`fbc8960`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fbc8960a2f39991300fa2a8b6c50b1128334ef8a)
- FIxed unicode issue with os.stat calls [`de5b2f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/de5b2f112552c87b2e361081a77def8050e403b5)
- PEP 8: Convert None comparisons from operators to 'is / is not None' [`3257c71`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3257c713d32d6e59b97db5f6536294352569ad94)
- linted mako [`8c60b69`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8c60b698794ae7feeb828c2c8eebb326d5df7855)
- Fixed unicode bug relating to os.path.getsize, resolves issues for setting episode statues and related functions. [`2c750c1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2c750c13b327627f44626686effb2e3f09461bff)
- Fix another stdout error [`9120677`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9120677d54d85e874a19ce9da5b98c0f9ee16e20)
- PEP 203: Replace assignment with augmented assignment [`e1d2e95`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e1d2e95ac09373e5e68ab10cf9c2830fd8e6d338)
- Remove redundant parentheses [`8d68fb9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8d68fb947ddb20b7826f18698ca67c42088fc4d9)
- PEP 257: Convert docstrings to triple double-quoted docstrings [`0fcb652`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0fcb652db77ea3f9e8b7786f227e637505a8f7cc)
- Remove unused imports in mako [`12d9056`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/12d9056c0ea41091dd5741b25c4c688f00e722e0)
- Fix forgotten import in webapi [`51c8c8b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/51c8c8ba3443b6ce4dbe538c49c2f59a6180050f)
- PEP 8: Move module level imports to top of file [`20393c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/20393c4854cb8509efd77d14582ac1d72d251e1d)
- PEP 8: Fix under-indented continuation lines [`b0f531c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0f531cba0990be886cdb4ceb2fa96eb8f565ed0)
- PEP 203: Replace dict creation with dict literal [`ff7907f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ff7907fc78ee6ad5bf0c50f8f9d908c5e2c469bb)
- fix indentation [`7f4ee8f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f4ee8f713c8e1e09965bebbd953cd27f3156b34)
- PEP 8: Remove excess blank lines [`9a76b25`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9a76b2559432cdafd4d5cbf19d84a47b609c1a5b)
- Fixed issue for post-processing on *nix systems [`22fcae6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22fcae6dbbc1deca5f237098725ae25d0a57cb35)
- Revert "Fix post processing non-ascii" [`42adf35`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/42adf3534fc24564cd03fe898db67b1f2ad5fa6f)
- PEP 8: Convert None comparisons from operators to 'is / is not None' [`3824491`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/38244917caa09601dfcd3c81926ffed3ff2c9b62)
- Remove redundant parentheses [`3e0c7cc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3e0c7cc6426239ce9d99dde2e4a92aeaa0b3376d)
- PEP 203: Replace list creation with list literal [`8589490`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/85894908e13df8c29f5fc9edda49db973f209a81)
- add aria-haspopup to force ie11/edge to emulate hover on these elements, also add superfluous span so that bootstrap-hover-dropdown correctly attaches the events [`0a8ec34`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a8ec34a21fb649d790ae3d288594306ab49b418)
- Remove errant spaces [`57b043b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/57b043be95f462fa39296de970e0070d6307455d)
- Remove errant spaces [`f90e9fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f90e9fe2bed09bc7228096316076c06be3a405e1)
- kat provider choice between anime or tv based on search type [`63866b6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/63866b6d6d13d6cbc0740d56d44210e16855e19f)
- fix unused imports and misspeled name [`31c1e45`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/31c1e4545c1aa23e4ce6916b63a5a852490ecbd6)
- FIX: Corrected code for log viewer to display when first accessing it. [`22b003d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22b003d0ed7d1533478c38e8c0d00411848e380e)
- FIX: Corrected code for log viewer to display when first accessing it. [`0066b61`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0066b6146d187183c2a8daa4d283f90dc5a73077)
- FIX: Corrected bug that was causing to many redirects when using a username/password [`a40fe0a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a40fe0accc8eba5333a23edd9739dd93425e7105)
- Fix starting as a daemon when running in unicode mode =P [`92fa0be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/92fa0bedfac753d1480c1bc917cafd00f1a39015)
- Updated readme [`5fce328`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5fce328af3dfa1dcf2873ce1ef42db8b61d2c16e)
- Update package.json [`f62dc65`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f62dc65bef699a151f3d2892c61cc4fa6026e84b)
- Update package.json [`379fad8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/379fad84bdc635685b8e20d437321a111df5860a)
- PEP 8: Convert comparisons [`63f96e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/63f96e461b8d3158d02d3761a131527895c04587)
- Remove redundant parentheses [`9e53168`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e531684f6e0a51ee2af63fd18f97bb901205407)
- PEP 8: Fix indentation [`8cd170c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8cd170c077fe219e4326fe8d9f97f536374271b6)
- FIx: wrapped os calls with ek calls for proper unicode decode/encode [`3a9ff9a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3a9ff9adcbbb1249626b30325726ba119865df92)
- Updated readme [`4a5fae4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4a5fae4719485b11e7c1eb7e9aa3dfb1f3534763)
- Whitelisted develop for travis-ci builds [`b41a8a6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b41a8a64e827a2465bfac26cab1b2c1e790ccc2c)
- make sure images and nzb data is downloaded as bytes instead of unicode [`1c96df5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c96df573d86df510cedfa14d99f491a4906d45b)
- add extra globals [`641754c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/641754cc91329954c339403ac8db9039ec1c11d0)
- Remove redundant parentheses [`c675674`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c675674cea4bf6a7d2f72cfaa376369ca9bde19b)
- PEP 8: Convert None comparisons from operators to 'is / is not None' [`922f763`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/922f763a5b38b8da1f28765997164f941e43e766)
- Remove unreachable code [`4b1d6a0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4b1d6a06b7966a180569791613085686a56292c2)
- PEP 8: Move module level imports to top of file [`91009f7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/91009f7555d3b5ecf3fe0d62532b8e3ee0472f34)
- PEP 8: Refactor variables that shadow built-in names [`d0702c0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d0702c002441376cfd4ad39d3525dd77e4f043c6)
- fix typo [`23f1c9d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/23f1c9d11600306c04e843ea49136ffeef272357)
- PEP 257: Convert docstrings to triple double-quoted docstrings [`6d8b748`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6d8b748b9fad5d7182bcba1c65e126d96e9c1f3b)
- update kat to use a mirror [`2d82a34`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2d82a34d7ef442872ffac93e9c25597d40aa2732)
- update kat to use a mirror [`df86983`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/df86983f2040ca5f3ec15fb2f8d0be596813ca22)
- PEP 8: Convert lambda expression to a def [`5d9cbdf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5d9cbdf7838544c49e2d674cf0961acbc5f37444)
- PEP 8: Convert membership test from 'not x in y' to 'x not in y' [`c12733b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c12733b81fc3ef285267a071a0dacb12a0d77f39)
- Update CPasbian URL [`88cfd53`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/88cfd533e870643a06be80858d53b6076f07bb49)
- Update CPasbian URL [`f950c5c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f950c5c73b80b9541e7f7f2bf721e01a729497ea)
- Revert force local timezone [`adb3058`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/adb3058cd64c4977fdf71c9d1b6dd67e81708560)
- Fixed issue with browse button missing on post-proc config view. [`9385abc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9385abc7624d1614662720965dd486f842e1f990)
- Update readme.md [`74500a2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/74500a248a39754624dc58170a86d5c398df72c7)
- Update readme.md [`d294e9f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d294e9faf48d45051a50d4e2cf3a0252c28d5b17)
- Combine duplicate conditional check [`fc62243`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fc62243ff54e4320fd08e954028364ac83e0ce72)
- PEP 8: Convert lambda expression to a def [`f273b45`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f273b45e5673fa3adefccb504d9739852d4fcc99)
- FIX: Corrected url routing parser code that was causing misc web items/services to not function correctly [`83ef6e0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/83ef6e09c754699db30afa77c45a8b6fdb083942)
- New feature: User can select episodes and delete them both from show and hard drive. [`b3da8d9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b3da8d931510a82cd42149b002bd40b10d3571f0)
- Whitelisted master for travis-ci builds [`d134454`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d134454b978467ac62c576e735f243090c7d7d28)
- Corrected travis-cl branch logfile reference. [`4c670ff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4c670ff419dd56425bf0dc243dcdac5a0cff56e9)
- Corrected travis-cl branch logfile reference. [`ee20635`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ee20635b5ea02b55a166ebe9e357d206bd85fb18)
- Corrected travis-cl branch reference. [`f82cc3e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f82cc3eeda571015d35a3f1cefb2115877173c0d)
- Fixed missing reference to remove test cache db files when running unit tests. [`7c91a80`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7c91a806818befa296c929697cdbb3c2844ae591)
- Fixed issue in shutil patch regarding missing ek reference [`2376d2c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2376d2c6719c37ed9d71b5888896f13554401f23)
- Fixed bug in shutil patch preventing post-processing from completing. [`22ea241`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22ea2414307d67de020bf208c1af9766b351f9b7)
- Fix typo [`e8c5912`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e8c5912099a266dd7006a3ed65ed4678c58d5b2e)
- PEP 8: Fix indentation [`54edd29`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/54edd2923589b40cc2df2babe0e49bac29a2df6b)
- change sbLogin to srLogin [`8c9515e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8c9515e66a26f46c2ddf4aa6df9547b5017e70ca)
- Remove redundant parentheses [`f4f5f55`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f4f5f55ebeac9b3d2b645e5033ecb5fe8cb77d65)
- Remove redundant parentheses [`bce75e5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bce75e5adacca952c15813c5754c310cdbb05ff8)
- PEP 8: Remove unused variable [`e51ec7a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e51ec7aba475078b24ec2a6cb0118ada7ffa9431)
- Remove redundant parentheses [`609e6d3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/609e6d329b1314c5de4d761cdbcfc3523dc6b3b7)
- Remove redundant parentheses [`fa1c8fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fa1c8fe3558cc18fd4509fbdf33c243ee5398150)
- PEP 203: Replace assignment with augmented assignment [`4767c90`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4767c90a0b13ca2bbacc6f1c2e45f6998a8772a0)
- PEP 8: Convert membership test from 'not x in y' to 'x not in y' [`8e1a17c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8e1a17caebb54d255e2822ac3d4076b42415d11c)
- PEP 8: Convert None comparisons from operators to 'is / is not None' [`48c5c76`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/48c5c76ab56bcd2a590d6a2f51ca07920662dbd7)
- PEP 8: Convert None comparisons from operators to 'is / is not None' [`ca2b8a0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ca2b8a07a1ab92ea48cf11b2a400c4361b6074c0)
- PEP 203: Replace assignment with augmented assignment [`ea5ffde`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ea5ffdeece4140e84e223f51437795b4c50ece7c)
- oops [`5f49688`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5f496885827bf88e4b24a4c94dc163dd016b2bca)
- oops [`0bfddc9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0bfddc9faa87b78cb5f04f01eaf40d753d4c11c9)
- PEP 8: Convert None comparisons from operators to 'is / is not None' [`a9ff03a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a9ff03aae3077899d9e59499ad99527dfa5c1bae)
- Convert to new style classes [`792ff3b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/792ff3bd9619254711192c3258631ee042f66ed8)
- PEP 257: Convert docstrings to triple quoted docstrings [`1ae38ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1ae38cec6ac9ec59a211a8bfd7d10ecbaa662596)
- PEP 8: Convert membership test from 'not x in y' to 'x not in y' [`c4cc2ea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c4cc2ea7d778030d7f13b485c2d8cc48adab60dd)
- Passing the showObj here is matching wrong shows! NameParser may be broken somewhere? [`ab64122`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ab641225e040e077bddc778b6a0c45c602cda118)
- Make ,only download spanish results disabled by default aka n00b proof... [`6c1b489`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6c1b489e0057c3fbb482c5a685c5f33eca7dbf4a)
- Please dont use funkym provider names, if someone wants to use it they will know what language it is for [`1b2062f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1b2062f90beace148ad735dbea3e5236f3da7cb4)
- Have to replace _ in the key check for imdb info also [`1352557`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1352557216703b982a0468ad33ef522004831b80)
- Have to replace _ in the key check for imdb info also [`307d1a6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/307d1a6559767bef4ce4989631b23958367c7e29)
- fix indent [`d58c59b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d58c59b7c50f91b2199c93c6b4884a38c97a45af)
- PEP 8: Remove blank lines for consistency [`13794b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/13794b2edfa7060df2f3e7730cefa9edbf541209)
#### [v4.1.0](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.76...v4.1.0)
> 1 November 2015
- fix propsal for 1097 - dropdowns not working on touchscreen [`#3045`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3045)
- fix several front end bugs with initial setup [`#3043`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3043)
- Added Musique Plus Network Logo. [`#3034`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3034)
- Improved BDRip recognition and indentation, removed WEBRip support (a… [`#3035`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3035)
- Added hd-space.org support [`#3031`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3031)
- Replacing tabs with spaces before giving data to soup. [`#3027`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3027)
- Check scene exceptions while PostProcessing [`#3023`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3023)
- Make massEdit UI consistent with other pages. [`#3012`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3012)
- Added GFTracker.org as torrent provider [`#3016`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3016)
- Avoid open mako cache issues and warn user to delete cache folder [`#3015`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3015)
- Hide pin from the UI [`#3014`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3014)
- Add "[PublicHD]" to removewordlist [`#3013`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3013)
- There isnt any Freelech torrents on tracker nor implementation [`#3008`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3008)
- Hotfix-3450: Fix airdate of 'Never' while avoiding Windows dateutil issues [`#2997`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2997)
- Fix Trakt message log levels [`#3002`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3002)
- Provider for Pretome tracker added [`#3005`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/3005)
- Fix issue filter - prevent issue SPAM [`#2996`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2996)
- Fixed scene quality auto pp not renaming, added bdrip, dvdrip, webrip… [`#2993`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2993)
- Fix link to rarbg from readme :) [`#2992`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2992)
- Fix Season folders [`#2971`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2971)
- Display show names while massEditing [`#2990`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2990)
- NextGen provider domain change - again [`#2984`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2984)
- Add Ratio to TorrentProject [`#2985`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2985)
- Add Ratio to Strike [`#2986`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2986)
- Add "-[SpastikusTV]" to removewordlist [`#2983`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2983)
- Add Ratio to BTDigg [`#2982`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2982)
- Fixed MTV provider specific issue with search [`#2981`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2981)
- Fix HDT AttributeError [`#2980`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2980)
- Make sure news var is defined before finditer on it. [`#2089`](https://github.com/SiCKRAGETV/sickrage-issues/issues/2089)
- Make sure news var is defined before finditer on it. [`#2089`](https://github.com/SiCKRAGETV/sickrage-issues/issues/2089)
- Make sure data is xml before trying to parse it with xmltodict [`#3507`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3507)
- Make sure data is xml before trying to parse it with xmltodict [`#3507`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3507)
- Don't use | for air_by_date or sports, especially if provider doesnt support | [`#3406`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3406)
- Dont allow "downCurQuality" after reverting a failed episode, should fix failed handling issue of replacing existing good files [`#1994`](https://github.com/SiCKRAGETV/sickrage-issues/issues/1994)
- Do not make torrent labels lower case for rtorrent client [`#3004`](https://github.com/SiCKRAGETV/SickRage/pull/3004)
- Fix listing associated files when folder name has [ or ] and confuses glob [`#1571`](https://github.com/SiCKRAGETV/sickrage-issues/issues/1571)
- Return False if no data was returned from getURL in NextGen login [`#2203`](https://github.com/SiCKRAGETV/sickrage-issues/issues/2203)
- Update mako from 1.0.1 to 1.0.3 [`d0e3a1a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d0e3a1a60bf76ff86abfd861e79061b6bb2f4961)
- Update mako from 1.0.1 to 1.0.3 [`d808199`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d808199cd8c6505082e3056bee5437ee1fab55cb)
- Fix mako cache bug [`8d98e18`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8d98e189be2cb15b1aea5370e8075ae33c234f9d)
- Fix almost all of the name_parser tests [`63e165c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/63e165cd5ec3fc7692ef8a39619735a41ff5ef17)
- Lint sbdatetime and fix some problems where returning within finally block can swallow exceptions [`51b058c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/51b058c62569202e2908a518f543e585ce0ab915)
- Fixed scene quality auto pp not renaming, added bdrip, dvdrip, webrip detection, fixed encoder detection with multiple codecs in file name [`42afe02`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/42afe02425a783dcc851b0f597e21faa1eebab79)
- Lint helpers.py and fix some problems [`a05be1d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a05be1dade4caed6c23bc267e9ab5118742a47ea)
- enlarge the clickable area for toggle drop-downs on touchscreens, but retain hover and click-to-link behavior for non-touchscreens [`dadfdca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dadfdca95c77c3a040777f38c3dd9ed748e077dd)
- Remove BOM @ncksol please change your editor settings [`15b3150`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15b3150bd4735ff76e86b44038c956f500e362f2)
- Remove BOM @ncksol please change your editor settings [`100a2dd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/100a2ddf1fdd1731a16d90fbc36cc587781c7309)
- wantEpisode was totally broken (may partially still be) [`0a0ce38`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a0ce3813cbe75c4d503ac01a1a76bab337d948c)
- Fixed session timeout issues [`8cdb0e9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8cdb0e9b9c9cfd74fc41755a935239137bd6cf54)
- Remove all occurrences of since it is not needed on Python 2.7+ [`9bdd070`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9bdd070a5bc6e122862eb25c531606f9e09507d2)
- Fix situation where category is not defined for an item in torrentz. [`900ec53`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/900ec53a865c2bfd0c0bf69f7ab2ee42a4f60a79)
- No need to import each provider in sickbeard/__init__.py [`ded601a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ded601a1277af2f918dfed173e8d2b4a8e875476)
- fix bug where if you update using autocomplete first, then the file browser is out of sync [`d9f62a4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d9f62a49c9d8d59265f4b60b722c131e8e134f8b)
- Fix log filter [`4258d06`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4258d06a14ac2633da66d77db787e3a1d8663162)
- Need to convert from datetime to ordinal and make sure is > 0! @duramato' [`6d24e4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6d24e4b54eaa64c72425d849e7496bf0f4551f56)
- Use tzwinlocal for sb_timezone on windows. [`1a53fff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1a53fff2283b1815144b4d3f6552fedc9a6012df)
- Fixup [`ef75a59`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ef75a599deda39b46a432a99323c440744c4c016)
- Fixup [`2613a73`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2613a73dad353a127d35876e7a4d5e5bbef8c202)
- Hotfix-3450: Fix airdate of 'Never' while avoiding dateutil issues on Windows [`0a6e4e7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a6e4e70306a9a4612d1b0c54f471adda8c7e60e)
- Update helpers.py [`0c906ac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0c906acdf2bc98fb565d27dda2a3efb65ce42309)
- do not cache notifications or file browser calls, fixes lots of weird UI quirks on IE/Edge [`ebf5527`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ebf552704b8df0b17dc14bbf5964508bf5d744a3)
- Fix updating imdb info for shows [`63ea63f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/63ea63fa6a268a41eb526baab9faa43831c12f1e)
- Missed specifying the parameter to replace in the datetime object, should have tested it better [`44651ae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/44651ae4004a5ca289532380d3a8a6780e16b1b7)
- Fix a bug where file would not PP a better quality when existing quality was unknown. [`9ba5154`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9ba51541da1d9be67c1bb3f84ae4be2dc14b5c6c)
- zzz [`e61aaf3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e61aaf37645e360e5527b4d0b44a532dea63976c)
- zzz [`5e38535`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e38535bc59d877f01562e38abb00b9e0e0804db)
- Updated description [`2e17e67`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2e17e6787a152ecfe65f8cc93ca50782af7c13d0)
- remove unnecessary init causing error on search settings screeen [`442e9c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/442e9c72ab5c58e1da0bd1ea4a59eb78207febcd)
- Move tornado into lib [`618737a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/618737a3b52e11866f20e76f1ee272cf16351aac)
#### [v4.0.76](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.75...v4.0.76)
> 24 October 2015
- Try to fix encode/decode in HDT title [`#2975`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2975)
- Added support for freeleech only torrents to Torrentbytes [`#2973`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2973)
- Torrentbytes provider fixes [`#2972`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2972)
- We are not checking for propers when snached_best [`#2969`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2969)
- Fixed #3432 [`#2968`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2968)
- Added Scene Quality naming pattern and capitalized release groups opt… [`#2967`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2967)
- Add [cttv] to removewordlist [`#2966`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2966)
- Handle server maintenance mode on TorrentProject [`#2965`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2965)
- Removed forced encoding, changed log warning to info, fixed some logs [`#2964`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2964)
- Fix broken flags in subtile settings and in missed subtitles [`#2963`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2963)
- Change line from error to warning [`#2962`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2962)
- Fix SiCKRAGETV/sickrage-issues/issues/3418 [`#2961`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2961)
- Fix SiCKRAGETV/sickrage-issues/issues/3418 [`#2960`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2960)
- Fixed pt-BR not recognized, fixed flags in subtitles settings, remove… [`#2959`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2959)
- Fix SiCKRAGETV/sickrage-issues#3416 [`#2957`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2957)
- Schedule/ComingEpisodes was not considering snatched_best and snatche… [`#2953`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2953)
- Add size to SCC [`#2951`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2951)
- Upped RARBG's cache checking interval to 10min [`#2949`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2949)
- Added legendastv subs provider, added login for subs (python), many b… [`#2945`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2945)
- SCC search improvements [`#2948`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2948)
- Add TorrentProject link [`#2941`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2941)
- Ups forgot import on TorrentProject [`#2947`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2947)
- Fix typo in log message [`#2946`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2946)
- Add RSS to TorrentProject [`#2944`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2944)
- Fix missing code when exception and pylint [`#2942`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2942)
- Fix multiple snatches when 'snatch notification' fails [`#2940`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2940)
- Should fix SiCKRAGETV/sickrage-issues/issues/3273 [`#2919`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2919)
- Change loglines to be SickRage [`#2939`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2939)
- Allow user to Ignore subbed releases based on language names. Used to be hardcoded [`#2935`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2935)
- Let user choose which timezone to timestamp file [`#2934`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2934)
- Update to Tornado 4.2.1 [`#2931`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2931)
- Fix custom quality alignment in Edit Show [`#2926`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2926)
- Update TorrentProject default trackers as some are dead [`#2929`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2929)
- Search only TV category on TorrentProject [`#2928`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2928)
- Make Edit Show page style consistent with other UI. [`#2911`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2911)
- Should fix #2894 [`#2918`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2918)
- Fix SiCKRAGETV/sickrage-issues/issues/3370 traceback [`#2914`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2914)
- Fix SiCKRAGETV/sickrage-issues/issues/3347 [`#2905`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2905)
- Use common code to compute the shows statistics [`#2898`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2898)
- Fix SiCKRAGETV/sickrage-issues/issues/3357 [`#2912`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2912)
- Temp Solution for SR DDOSing TorrentProject [`#2915`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2915)
- Add NzbIndex ,update xem icon & add torrentz icon [`#2904`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2904)
- Added Super Écran network logo. [`#2903`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2903)
- Fix SiCKRAGETV/sickrage-issues/issues/3342 [`#2900`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2900)
- Remove some unused imports in webserve [`#2899`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2899)
- Remove archive first match check from displayShow [`#2901`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2901)
- Fix SiCKRAGETV/sickrage-issues/issues/1638 [`#2895`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2895)
- SiCKRAGETV/sickrage-issues/issues/3335 [`#2897`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2897)
- No point show Logs & Errors [WARNING] when log show only warnings [`#2896`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2896)
- SiCKRAGETV/sickrage-issues/issues/700 [`#2893`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2893)
- Saving downloaded subtitles with utf-8 encoding [`#2894`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2894)
- Provider domain change - again [`#2846`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2846)
- Fix SiCKRAGETV/sickrage-issues/issues/3177 [`#2892`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2892)
- Fix SiCKRAGETV/sickrage-issues/issues/3319 [`#2889`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2889)
- Fix SiCKRAGETV/sickrage-issues/issues/2383 [`#2891`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2891)
- Fix SiCKRAGETV/sickrage-issues/issues/3286 [`#2886`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2886)
- Hotfix Kat [`#2879`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2879)
- Hotfix TBP [`#2878`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2878)
- Try to fix HDT 503 error [`#2877`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2877)
- Try to fix https://github.com/SiCKRAGETV/sickrage-issues/issues/700 [`#2876`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2876)
- Fix SiCKRAGETV/sickrage-issues/issues/3297 [`#2875`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2875)
- Added 2 network logos (TV5 & TV5 Monde) [`#2873`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2873)
- Fix SiCKRAGETV/sickrage-issues/issues/3296 [`#2874`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2874)
- Change "Authentication Failed" to warning [`#2872`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2872)
- Fixes #3282 [`#2870`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2870)
- Handle ConnectionError [`#2868`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2868)
- Added w network logo [`#2869`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2869)
- Fix SiCKRAGETV/sickrage-issues/issues/3219 [`#2859`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2859)
- Change default values for new install [`#2867`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2867)
- Hide enable_backlog for dailysearch providers only. [`#2865`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2865)
- Make default timezone as local. Force 'local' for existing users [`#2863`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2863)
- Fixes SiCKRAGETV/sickrage-issues/issues/3274 [`#2860`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2860)
- Added missing Canal D network logo. [`#2856`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2856)
- Fixed relative paths [`#2850`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2850)
- Finished implementation of checkbox, fixed #3263 [`#2847`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2847)
- Added support for subtitles without country codes, added checkbox des… [`#2844`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2844)
- Change ' Refusing to change status of' to WARNING [`#2845`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2845)
- Hotfix hdbits [`#2842`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2842)
- Fix SiCKRAGETV/sickrage-issues/issues/3229 [`#2841`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2841)
- Added some missing network logos [`#2840`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2840)
- Replace SSL Error with a url with information. Disable issue submissi… [`#2838`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2838)
- Dont stop PP if any notifications fails [`#2839`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2839)
- Updated subliminal to 1.1.0.dev0, added no_setup patch, added napipro… [`#2834`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2834)
- Lower words while comparing with title [`#2832`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2832)
- Fix SiCKRAGETV/sickrage-issues/issues/3248 [`#2833`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2833)
- Add option to only download english releases on TNTVillage [`#2830`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2830)
- Merge pull request #2968 from medariox/develop [`#3432`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/3432)
- Fixed #3432 [`#3432`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/3432)
- Check that show has a network and air time before trying to convert airdate/time [`#3007`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3007)
- Wrong var name in mede8er [`#3398`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3398)
- Display free space in human readable numbers [`#2930`](https://github.com/SiCKRAGETV/SickRage/pull/2930)
- Limit twitter messages to 140 chars [`#3388`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3388)
- Error was already formatted [`#3386`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3386)
- Merge pull request #2918 from medariox/develop [`#2894`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/2894)
- Merge pull request #2876 from fernandog/skipping_char [`#700`](https://github.com/SiCKRAGETV/sickrage-issues/issues/700)
- Merge pull request #2870 from medariox/develop [`#3282`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/3282)
- Fixes #3282 [`#3282`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/3282)
- Merge pull request #2847 from medariox/develop [`#3263`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/3263)
- Finished implementation of checkbox, fixed #3263 [`#3263`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/3263)
- Check that the file being processed exists after unrar. [`#3252`](https://github.com/SiCKRAGETV/sickrage-issues/issues/3252)
- Updated subliminal to 1.1.0.dev0, added no_setup patch, added napiprojekt subtitles provider, fixed #3251 [`#3251`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/3251)
- Update dateutil to 9645c3d [`a4c9ca2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4c9ca2af5f6e84c0206355fc37ffe2bacf6e240)
- Fix bad encoding in hdt [`0c8d906`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0c8d90688a1f4969a45de8ad2ab52db005870ac4)
- Renamed variable _save_subtitles [`e25aa88`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e25aa88275ee1b16a5851a20608d9bd05b8cf5ea)
- Clean up, fix, and improve metadata creation for all metadata types [`5af7e45`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5af7e45100feaa3ea8013003ae3849b944710b86)
- Clean up, fix, and improve metadata creation for all metadata types [`0207ed9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0207ed954b3654ae3cdd1aec60b486b1cfa25a36)
- Reorganize and reword PP settings page. [`e1f5c5a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e1f5c5a4506c6888f8536503a5aa6f0a11d0c590)
- Reorganize and reword PP settings page. [`7a8a1b6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7a8a1b6c4d29dc40095e2e5c58becc41d656f4c8)
- Do not interfere with the dateutil timezone info when updating network timezones [`9e5af4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e5af4b275cc6ef6c5b63c7e27ab3d77ef045b5f)
- Remove findProper override from frenchtorrentDB provider\nRemove self.enabled redefinition in all providers [`5e580fb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e580fbd6e0c285ac3de122dfbccbd05f2b081bc)
- Remove code redundancy [`97a323c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/97a323c9d7af1d5ffdbdf53c9b74dc5f4643b6ed)
- Remove findProper override from fnt provider [`69676c8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/69676c8fb80c75bcee67eb4bab82fa2beef09c7f)
- Clean up unused imports in alpharatio [`a96404f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a96404fc18f07ac1325c9093e6b2ded893664be3)
- Remove findProper override from cpasbian provider [`4337752`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/43377523400f2d58cb5231757156e7eb42cbba1a)
- Remove findProper override from bluetigers provider [`4a6918a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4a6918a8458e078e5879b0ec815f83e1bcf2d1b7)
- Remove findProper override from bitsoup provider [`7e1cdb2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7e1cdb23b7e0c26779beb0619f2bb75038785b5c)
- Remove findProper override from extratorrent provider [`d32b2cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d32b2cb7d86391b0b4f73542c00aefd309555175)
- Fix bad indent for btdig. Clean up unused imports. [`6898d78`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6898d78eaae9ee897d4967d94cfe386db339ba6a)
- Remove findProper override from bitcannon provider. Remove unnecessary encode/decode [`8937ea1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8937ea152243c1aed3629b05852cea8da1f00937)
- Move nzb item parsing into the nzb provider class and handle exception better [`dbddd3e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dbddd3e69473b372ccd6d49e6b177f0dea8e85f5)
- Missed a place to remove non-release groups [`56bedea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/56bedea6cd36bd4d1adf83cbc10a95bd6f08a3fe)
- Fix nextgen, allow setting minseed and minleech [`08e7e59`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08e7e594de40fa4286a7345a1801913010fa4bc1)
- Remove getQuality override from hdbits provider, some linting [`676f999`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/676f999dcf192b3c4e5cc8b97cd9c0be7f301939)
- PR#2911 - move archive setting to "Main" tab. [`a14a390`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a14a39018d33fb784c245ef290ce0aa6d0349f03)
- Fixed pt-BR not recognized, fixed flags in subtitles settings, removed useless code [`a5a15a6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a5a15a68ceaa676ac163bb1d64c2dea8a3ffb1fa)
- Reorganize and normalize name quality detection a bit [`e3dfa7a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e3dfa7a872d7f53e9430aceb66ba298e710ca911)
- Update readme.md [`a78b842`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a78b842dcdfcee16cabd6401b86b4d93a558d61d)
- change domain for provider NextGn [`d7fb443`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d7fb443f1eaf711ef754336bb8939beddef1d141)
- Handle jackett/torznab in client direct connect as well [`ec83bc3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ec83bc3b270c441a2f7b3b3eae7187d446feaadb)
- PR#2911 - fix custom quality alignment [`588060e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/588060e53f2b66e7e21af39221f72fd934010c0e)
- We have no requirements other than Python 2.7.10 [`e7445e9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e7445e9f0dd919949164964eda5bc811f766316c)
- Fix wrong search string in scc cache/rss update [`b88c44b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b88c44bf59b691ad1a663190b2a26ee0f469bfc5)
- We have no requirements other than Python 2.7.10 [`57a31a6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/57a31a6ca5fbceedf75682a50d94fe66bcb5b162)
- Comment out useless log spam [`199d3b5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/199d3b5f358649899e638b5ec92572652eed15d2)
- fixup [`363cc4c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/363cc4c6f49b176be23aa0a4c0367e21e6eec403)
- Opps again... [`34e418c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/34e418ceb9ebb54e38a7fb686ff628dcf42742b7)
- Revert "Handle ConnectionError" [`1a08539`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1a08539d3ef2a341517643dcded6e626eb02e12c)
- Disable logging with print in hachoir_core so pythonw.exe isnt failing. [`a57bbd0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a57bbd095690ef666d2d7360e4500cc7f9ac489b)
- Just format to minimum 2 digits in episode search strings for anime, follows scene [`3270086`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/32700860f23ce61c08c9c089501bf9fddd904b07)
- Change hardlink line to warning [`1704872`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1704872b8ee23c7adaa35a46dee3b3d509785b25)
- Fix Extratorrent encoding [`d41574c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d41574c9ae34be69267160dcd2fdc1563dc653cf)
- Revert "Fix magnets from torznab/jackett not registering as multiple trackers in receiving client" [`8024143`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8024143e9e1cd1c6a4c300ca2c4633d7984547c4)
- Fix magnets from torznab/jackett not registering as multiple trackers in receiving client [`fb3c81d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fb3c81d4d86af905a1887675f5ba3e91836ea946)
- Update libertalia.py [`2127259`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2127259fa33a591bd207596b2ba6cf52570fcd87)
- Opps, committed an error. Fixes tvdb searching [`d09ca17`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d09ca1705c776f3a8ef6697775b53095153a205e)
- Revert adding all_tests.py [`32973f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/32973f480d0a78c13fb1d18de601c1b19855824e)
- Fix typo [`7f61f16`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f61f16695c4b6bba549a3adb5f573ef3efddaae)
- Handle unicode titles better in bitcannon [`a00dab6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a00dab6f67c7b4a93eefd44482ccd114d55c6fc3)
- Ups forgot import [`b14e4d0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b14e4d08b9c9e5ddfa9852caaaceee4f234c3c9e)
- resolved conflict in nextgen provider [`1e9a23f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1e9a23fb057f7b9527765979730f413342d78be7)
- Return when no trackers in bitcannon [`60f5c2b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/60f5c2b101c400b3afeaeb5a0708cd22d094386c)
#### [v4.0.75](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.74...v4.0.75)
> 10 October 2015
- Removed silly feature [`#2825`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2825)
- Fixed bug with empty path, make sure path exists on refresh [`#2821`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2821)
- Added the RDI network logo. [`#2822`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2822)
- Fix SiCKRAGETV/sickrage-issues/issues/3242 [`#2815`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2815)
- Fix tokyotoshokan [`#2816`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2816)
- Update sublimnal to 1.0.1, subtitle logic in subtitles.py, much more [`#2812`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2812)
- Check sockets timeout and fix log messages [`#2804`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2804)
- Fix SiCKRAGETV/sickrage-issues/issues/3231 [`#2808`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2808)
- Fix an issue with quality pill title [`#2809`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2809)
- Fix boolean values in API [`#2805`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2805)
- fix typo : downloadURL should be download_url [`#2803`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2803)
- Added back all network logos... :( [`#2801`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2801)
- Fixes SiCKRAGETV/sickrage-issues/issues/3215 [`#2800`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2800)
- Fix SiCKRAGETV/sickrage-issues/issues/3223 [`#2799`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2799)
- Fix kodi 12+ metadata more. Eliminate an error, and stop overwriting watched state. [`75f1466`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/75f14668b73e07b0cf64ed28c9bd72430c5208f8)
- Fix nonetype error on torrentproject, by checking if there was data returned from getURL [`caa7915`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/caa79156e5cb27ba400d7a1587f0d5f93139929d)
- Revert "Revert "Update xmltodict to v 0.9.2"" [`4b0584d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4b0584d10e966397c1f1079b3351a4aee44c0f15)
- Revert "Update xmltodict to v 0.9.2" [`1c280eb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c280eb61099f5d566ca96c14bafb01e6672067e)
- Make sure to replace , and make sure _cleanData in tvdbapi is operating on a string! It was trying to replace chars in a datetime object that was not formatted to string yet. [`e2f6b1b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e2f6b1b925d37f8d69899e944378c5206e013f01)
- Fix search/snatch for btn (still needs a rewrite though) [`40670c6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/40670c6efcafec342433b77e030406008c9cd2e2)
- Removed language restriction from xem allNames call and ensures the search string generator can return searchstrings for anime shows even if the whitelist and blacklist is empty [`e8c4d88`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e8c4d88d32be934ebcdbf374d3af88269be88bb0)
- Fix incomplete format in omgwtfnzbs [`a315f2f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a315f2fb71c71fd98d2d13d03a3d8f505d858946)
- Fix mismatched variable name in libertalia [`483ccd9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/483ccd9ace838439f4d541f8029be6e9b41ef883)
#### [v4.0.74](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.73...v4.0.74)
> 8 October 2015
- Add try|except for trakt_api.traktRequest and fix log messages in [`#2792`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2792)
- Fix some of the log messages from tv.py [`#2793`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2793)
- Filter another recurrent issue [`#2795`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2795)
- Add "searchURL" log message to KAT/TPB [`#2791`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2791)
- Refactor /comingEpisodes/ to /schedule/ in GUI and save sort [`#2784`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2784)
- Parse size from RARBG results [`#2785`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2785)
- Add result sorting for providers [`#2776`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2776)
- Removed one logo to many. [`#2782`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2782)
- Added missing Belgien network logos. [`#2781`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2781)
- Removed TVRage network and unused logos. [`#2779`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2779)
- Avoid submit mutliple ascii errors [`#2777`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2777)
- Fix Strike NameError: global name 'items' is not defined and parse si… [`#2775`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2775)
- Fix Torrentproject: ValueError: too many values to unpack [`#2773`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2773)
- Fixes SiCKRAGETV/sickrage-issues/issues/3176 [`#2770`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2770)
- Hide filter row on Schedule page [`#2769`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2769)
- Fix "Select Columns" button on Schedule page [`#2768`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2768)
- Mass change providers [`#2754`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2754)
- Fix bug causing redownload of download episode if quality is below th… [`#2764`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2764)
- Add column filter widget to schedule table [`#2763`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2763)
- Don't wrap quality pills [`#2762`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2762)
- Add more history page limits [`#2748`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2748)
- Remove line between text and caret for split items [`#2761`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2761)
- Don't show logout option when auth is disabled [`#2760`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2760)
- Only show appropriate error submenus [`#2759`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2759)
- Update PyGithub [`1f4f611`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f4f611bcda1d54c8bfcbf43bafc449ca8064a37)
- Fix log messages [`ee72b0f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ee72b0f40131b2239accbf5c58936a60cbb41847)
- Clean providers [`ff9d636`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ff9d636104a86efd91cce3fce315549bac40fa49)
- More changes [`a6e23cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a6e23cbb2e8e08897da675c2a1445f6fba76f9d0)
- Reorganize imports so tests work individually [`70a6da1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/70a6da11f9029653d5045ea79fbcedb30422544c)
- Refactor /comingEpisodes/ to /schedule/ in GUI [`5e90804`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e90804da5d5d734f914b9809b85ae8852bc3ced)
- Moved js to new directory [`b393115`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b393115f811b3848df2e68e6f4c465b2dc5149e7)
- Fix comingEpisodes sorting [`9410aeb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9410aebfc54abf8c4445ea4b44c9046cec03feb2)
- More updater changes... [`6362464`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/63624649b2d9e67f6dd36da4e1e201abc95c539c)
- Check xmldict exception [`b18b66a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b18b66ac95fa9a37833377fa339d58f7bdedbba0)
- Make sure the dir exists when checking for free space in root dirs and tv download dir. If it doesnt exist display "Missing" [`b8db289`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8db289dd5b08811661f9208858db3163a1229ac)
- Update contributing.md [`c542698`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c5426984a148e00e4af4b6dcc0054c4ac913e1ed)
- Fix bug causing redownload of download episode if quality is below the highest possible quality (even if archive on first match) [`f70e72c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f70e72cb865d9751539035a40913e47617b6d1c6)
- Use regex to detect and match mako errors in issue submitter, temporarily [`49dfc22`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/49dfc22ec0c4a8e1ba4b3bd6f674df44cab54d6b)
- Make new nfo actually write the actors. updates of existing nfo still doesnt work. [`2e9005e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2e9005e0673ffd2d6012e2a8a0a468e6758b42e3)
- fix build second error [`1c57cce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c57cce2d73d9775acb01f256e07d22a93f4c1f4)
- Only show non-proper log as debug [`3d6ba28`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3d6ba285824d41e8bca392383a88852d5a335379)
- Fix syntax error breaking build [`39f4c8f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/39f4c8fdf5738f7bd4d132a125922d1048129ba0)
- No wrap Ends column [`c1dc7ec`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c1dc7ec4b45e252acb99dd1c4152e9c711f7c146)
- pushurl error on some installs? strange. [`c92f56c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c92f56ccfcbbdb22b5098113e0ec95a0cb6fccbf)
- Changed torrentbytes icon [`416b27a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/416b27a8f756eef7897c7e34447460cd381dca7c)
- Fix provider images [`b59169e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b59169e66ef9553b39fb4f6d3bb87dbe403e65dc)
#### [v4.0.73](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.72...v4.0.73)
> 5 October 2015
- Add [EtHD] to removewordlist [`#2752`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2752)
- Add SATRip to SDTV [`#2751`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2751)
- Clean warning logs for t411 [`#2746`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2746)
- Move 'Archive on first match' closer to 'Quality' in editShow [`#2739`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2739)
- Redirect to /errorlogs/viewlog/ when clearing errors [`#2741`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2741)
- Moved to .build [`eb54f65`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eb54f6503aa2b85f1946e3971302cd0730cfaf00)
- Removed unused code [`fb580b9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fb580b9bffe1b1a6738485584e43b8e62d85ee63)
- Handle locked issues in issue submitter, better logging and ui notifications for submitter [`582b594`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/582b594a4f054a190e4927e20a573f627296832f)
- Clear cache/sessions and cache/indexers on restore [`aeee484`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aeee484c8f5bd9e49637ab67f88645314ac13d4b)
- Fixup .gitignore [`ff6e63c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ff6e63ced56b3955031338c6d7ada89571d4f04a)
- Clean warning logs [`320aa08`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/320aa080b6df17ccbed4bdae84731fee0c7c1b7a)
- Fixes _bower.js being tracked [`3334d88`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3334d881ffde5902fa37474ce6b886934adefc5f)
#### [v4.0.72](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.71...v4.0.72)
> 4 October 2015
- Wrap time calls with try/except to fix #3095 [`#2738`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2738)
- Fix typo and grammatical error [`#2733`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2733)
- Add 5 most recently accessed shows to Shows menu [`#2731`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2731)
- Merge pull request #2738 from VinceVal/fix-issue-3095 [`#3095`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/3095)
- Wrap time calls with try/except to fix #3095 [`#3095`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/3095)
- Remove manage submenu. Only use submenu when it is something not in nav. [`dcaabc1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dcaabc143cd754c4d39d1281bec4464fdd787a20)
- Fixes viewlog disabling inputs till refresh [`057c937`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/057c9378a56bbc9e3105b5436b8b4fa8e63d37c6)
- Fixes broken table sorter [`c12e692`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c12e6926e5745c04c86dae585bdd646817189027)
- Removed push header fix [`1700c06`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1700c060c3fc528af09f9693822101290e8c958e)
- Fix title and header on missed subtitles page. [`0824eb5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0824eb50e521e08b5e6a89b34ce1142fe5384883)
#### [v4.0.71](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.70...v4.0.71)
> 3 October 2015
- Rename 'Coming Episodes' to 'Schedule' [`#2726`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2726)
- Navbar non-dropdown background hover [`#2727`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2727)
- Move log menu to tools menu and update tools badge [`#2725`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2725)
- Render a badge with error count on Logs & Errors [`#2715`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2715)
- Add support for x264 and h264 [`#2667`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2667)
- Respect timezone setting in displayShow, backlogOverview [`#2721`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2721)
- Fix the topmenu for News and IRC [`#2720`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2720)
- News notify and tools menu [`#2717`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2717)
- Change default log menu href [`#2716`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2716)
- Notify user when new news exists [`925075d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/925075d5b30e40eceb18d0d8d8b69e0812d6b677)
- Update readme.md [`44a2fef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/44a2fefd4147aec84bd13835d16eba43907fa669)
- Update isotope [`f542e17`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f542e17117472dbb29762fab211e9bfa2fc76840)
- Fix build, rawHD wasnt matching [`06d4866`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/06d48664c0c8d933e5d838f2a0957ebaccfe9504)
- episode can be None when using abs number. No need for this log line anyways. [`26307a7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/26307a7c3fc9f1b50f882946eb56749e1779bcf8)
- Missed try/except on a date format in unrar2 [`8d6431c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8d6431cf3cc6336bb7867184cbcebb9409ced009)
- Last fix to unrar2 [`1f0e30e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f0e30ef55d3c865ce81c49bb66bafc0482a8140)
- Didnt mean to commit this [`09b7131`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/09b7131d595c0c5c71b8bd87abcfa9319a4969ce)
#### [v4.0.70](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.69...v4.0.70)
> 3 October 2015
- Remove redundant buttons from various pages [`#2675`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2675)
- Create split navbar dropdowns [`#2713`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2713)
- Fixes SiCKRAGETV/sickrage-issues/issues/2368 [`#2712`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2712)
- TTN: Fix category & search_string [`#2703`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2703)
- Fix Chrome rendering issue on episode status page [`#2698`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2698)
- Update six lib to 1.9.0 [`#2685`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2685)
- Update xmltodict to v 0.9.2 [`#2683`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2683)
- Fixes SiCKRAGETV/sickrage-issues/issues/3056 [`#2684`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2684)
- Fixes #3049 and #3024 [`#2681`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2681)
- Fix SKIP_REMOVED_FILES not saving [`#2680`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2680)
- Fixes SiCKRAGETV/sickrage-issues/issues/3039 [`#2679`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2679)
- Fix ET cloudflare issue [`#2678`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2678)
- Make navbar dropdowns clickable links [`#2674`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2674)
- Make the "Select Columns" buttons consistent [`#2676`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2676)
- Fixes class attribute on navbar items [`#2677`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2677)
- Show season dir in File Name column on show page [`#2673`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2673)
- Fix .seasonheader on rename page with light theme [`#2672`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2672)
- Convert "Shows" back into a submenu [`#2671`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2671)
- Fix typo [`#2669`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2669)
- Check if is safe to update when user click "update" in UI [`#2668`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2668)
- Change comingEpisodes keys to be aligned with API [`#2665`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2665)
- Add archive first match to 'Manage' [`#2664`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2664)
- Add TVMux ,WebMux and BRMux [`#2663`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2663)
- Restores support to ignore embedded subs, '?' will now be replaced by… [`#2661`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2661)
- Fix SiCKRAGETV/sickrage-issues/issues/2905 [`#2659`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2659)
- Fix SiCKRAGETV/sickrage-issues/issues/2769 [`#2658`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2658)
- Improve the way quality class is generated [`#2660`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2660)
- Add DVDMux & BDMux as valid SDDVD qualities [`#2652`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2652)
- Add missing config settings to UI [`#2657`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2657)
- Fix for when seeders/Leechers is "---" instead of a number [`#2655`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2655)
- Fix issue #2988 [`#2653`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2653)
- Use enzyme to detect embedded subtitles instead of subliminal [`#2650`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2650)
- Merge pull request #2681 from medariox/develop [`#3049`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/3049)
- Fixes #3049 and #3024 [`#3049`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/3049)
- Linted formwizard [`02eca03`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/02eca03bc35fa8c1f81d0b31a894cca5c89ec802)
- Removed fancybox [`6688c76`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6688c76a6144ed9dd1a18e42c2954e5662410702)
- Converted to meta function [`3e8cba7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3e8cba7cc1e82755a8d3d67be7eec52f82f6ae22)
- Update unrar2 to 2fe1e98 [`f458db7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f458db75892ea31712426221956b1f1ecb379fff)
- Deduplicated metas [`1ad2bc9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1ad2bc9903277ad9cccb69d587ee576b6cb683c8)
- Restores support to ignore embedded subs, '?' will now be replaced by default langauge (see conditions) [`e9a4b4a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e9a4b4a08f20a9625704b4e856db45b5c28a49ed)
- General code cleanup [`4357691`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/43576914496bfc2177a184e0179d97a6aa3c58b9)
- Removed auto refresh [`1800191`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/180019141dc101ad14e1562452e2c1175eeff684)
- Updated jQuery, added bootbox back [`c0d8a8c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c0d8a8ccb92aae4a68f4b9d097966a53543b6002)
- Remove skip remove from PP. Not PP setting [`d600f76`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d600f76226b09b3f51f6e1d774ba9313d5cc7e65)
- Removed old jQuery and momentjs [`c1fdb0f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c1fdb0f17726bfa30b7e566fc9e75948dcb89ac3)
- Revert "Check if is safe to update when user click "update" in UI" [`30eba5e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/30eba5e5320fc79457cd6dda3d3e2db30a7cb4f6)
- Check if is safe to update when user click "update" in UI [`c08c1e5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c08c1e57bb942fa1bf778a1349506130064c5d70)
- Fixes cursor not changing back to default after logs load [`812d572`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/812d57262c5fdb042d96adb3e02b62a43f8621cc)
- Moving all data files in a seperate data/ dir [`bed33d6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bed33d600ae551ce8bcf1345d2f3f4dbf578d090)
- Removed unneeded comments [`04a2d79`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/04a2d79f4498b04096d8b6e91305195013720ee8)
- Use os.path.join instead [`617204f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/617204f55626ee278ce4e6332f69e7629babbb29)
- Fix cloudflare issue [`1d18d4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1d18d4b264ec7c7f56e5b2adbc1e5069789572d1)
- Moved form wizard to main libs [`328c392`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/328c39288ca73c7caaf94bd9a1f9e602a021268e)
- Moved formwizard [`6b1b643`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6b1b643c6a6ac0744102f921f89a884622a6173b)
#### [v4.0.69](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.68...v4.0.69)
> 29 September 2015
- Add missing check for auth to _doSearch [`#2646`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2646)
- Fix urlsearch [`#2645`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2645)
- Add ExtraTorrent provider [`#2641`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2641)
- Dynamically get torrent trackers instead of hard coded ones [`#2636`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2636)
- Finalize extratorrent provider [`1b19c68`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1b19c68920350373435d2c401bdd08b66643e76a)
- Ignore .@__thumb on qnap, and dont log it. [`9ed9872`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9ed9872fb97521e0b80d5f8f74ce84176bad0287)
- Update readme and contributing about feathub [`36df8b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/36df8b3314dfcbf8a1b5e44f6caeda95c8400a33)
- typo, in a comment (i know silly commit, right?) [`8030d38`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8030d385ea4d52be870f2a7a276cc1d5892c7c0f)
#### [v4.0.68](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.67...v4.0.68)
> 27 September 2015
- Fix for wrong subtitle language codes [`#2626`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2626)
- sbRoot is no longer used anywhere [`#2628`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2628)
- Fixed qualityChooser not expanding custom qualities fields [`#2625`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2625)
- Add TorrentProject provider [`#2621`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2621)
- New API builder [`#2581`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2581)
- merge #2620 [`#2620`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2620)
- Updated 6box logos & added ALL brazilian networks logos [`#2614`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2614)
- Fixes subtitle recognition with sigle language [`#2613`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2613)
- Added 'archive on first match' option when adding a show [`#2612`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2612)
- Add "srRoot" template variable [`#2611`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2611)
- merge #2609 [`#2609`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2609)
- merge #2610 [`#2610`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2610)
- Unused logos and add missing ones [`#2601`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2601)
- Fix info icon on custom naming legend [`#2603`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2603)
- Linted [`20b78fc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/20b78fc5414fd48ff96d7cff69645ad8e73fb675)
- Moved from sbRoot to srRoot [`c2fa507`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c2fa50773424d7dab34b74e75550cf87d0138564)
- Moved more js to own files [`34ec2cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/34ec2cb0c5d375cf36d15b307e9ebdb6c87c3fd3)
- Remove fuzzydate and library [`247489c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/247489c5b3e405c832fa0816a883100c161c4c09)
- Fixed isodate [`d42c7fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d42c7fe20711bd81c69ef3e93bce2e1ca4627657)
- Update pylockfile to 4a7a20d91c44d2be6396be5fc64d27b0b5afa4e2 [`af4132e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/af4132ec3641aca370a575936cc1cf8e3b613248)
- Linted config and qualityChooser [`06b6f0c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/06b6f0cc0c3c9ee36c5f803b7deb26cc850dbec0)
- Moved js from files to own [`e303308`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e303308c14102ce1da079e8056ed2b3e39f9ac73)
- Implemented saving as default archive on first match option [`4943b78`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4943b78b8e9a595c404dad6bda1e45bfb5029428)
- Fix subfolder not created for new shows [`ec5c7ec`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ec5c7ec1f57d02d2d1cefcd126111977a8cf9874)
- Preliminary support for tvdbid search on indexers. [`0f3f509`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0f3f50909751762d4bf33c06fc88b18a9754be21)
- Fixes config_subtitles [`7f38008`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f380086aafb119ccdc40d99a18ca8c4d30391cd)
- Fix not being able to set status to compound archived qualities [`3c383d8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c383d856a6475320f1f489ca8322c8d13e1803b)
- Update pkg_resources.py [`139b3f5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/139b3f5f145f0ad3553e4f6a4a4a8d63ed56c39b)
- Fixed two bugs introduced int PR #2612 [`04caa3d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/04caa3d489ea6fa985dc28fd21778757b40d7941)
- Force CacheControl to use MkdirLockFile. [`7b584bc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b584bc9702a03b922a515f4eeb405384c1ed624)
#### [v4.0.67](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.66...v4.0.67)
> 25 September 2015
- Sic Logos & TVcabo logo [`#2599`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2599)
- Add log message about discarded torrent [`#2598`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2598)
- Fix "Initial page" option [`#2593`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2593)
- Add RTP networks logos [`#2594`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2594)
- API images fix [`#2596`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2596)
- Fix history limit and save on change limit [`#2592`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2592)
- Add more values to history limit [`#2591`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2591)
- Image API commands now return the correct Content-Type [`#2589`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2589)
- Improved API docs #2588 [`#2588`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2588)
- Don't format JSON before sending the response [`#2582`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2582)
- Fix page url on shazbat.tv [`#2579`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2579)
- Show SR datetime in the bottom of page [`#2584`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2584)
- Add tip to timezone setting [`#2583`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2583)
- Fix webpage url for BTN [`#2580`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2580)
- libertalia login unsuccessful warning [`#2575`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2575)
- Don't show 'add' button in imdb popular if user already have the show [`#2577`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2577)
- Fix dailysearch not respecting timezone setting [`#2570`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2570)
- Add webage url to btdigg [`#2573`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2573)
- Show timezone setting in the 'Airdate' column in comingEpisodes [`#2571`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2571)
- Really fixes SiCKRAGETV/sickrage-issues#2774 [`#2569`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2569)
- Fix SiCKRAGETV/sickrage-issues/issues/2910 [`#2567`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2567)
- update xthor add quotes to search string [`#2565`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2565)
- Move js and lint [`2df5e71`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2df5e7134fcc2ff04044e0e8671f21b3de3615fc)
- Use a single tablesorter function for both anime and normal [`aed837a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aed837aa407994ceaa14971bc20d27210dfcafb9)
- Fix lint issues in home and history js [`4fb2c51`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4fb2c5104e8659c78de716487225f69413525691)
- Restore was only processed when console logging was enabled! [`070e1ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/070e1ba55b74f2d5cbf41602c690cdf55fb0576c)
- Restore was only processed when console logging was enabled! [`acb6a81`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/acb6a817a32477781e53b48686d1dfa6b2a7e1a4)
- Fix funky url [`1331981`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1331981df3a721c301fe7c64734611c0423e9f42)
- Move metas to their own block [`97c28bc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/97c28bc4a5d8d0e46fec7dcd5e99e47838f5511f)
- funky url [`2e73a22`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2e73a22b445c023e4351f88b371142573f2b394e)
- Don't show 'add' button if user already has the show [`5144fc5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5144fc503dea4f097695326546f4d914a875cedc)
- Fixes in js [`cd956e0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cd956e05dde948d592e03de2ec7cbc00c9106b8b)
#### [v4.0.66](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.65...v4.0.66)
> 22 September 2015
- Fix linting in newznab.py [`0736f58`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0736f58383357abac1fda1b61a3f18b4ff9d46ad)
- Fix some out of order paramters in calls to private pushover notifier methods [`657ffd7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/657ffd7c4e61d32cecde009541cd25476579b254)
- Fix some out of order paramters in calls to private pushover notifier methods [`561dde9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/561dde9012910234700f5abf54f99cead3079b1b)
- Fixes blackwhite list loading before jQuery [`92682b8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/92682b8bc05d4d9440cf34575d0d1ce0df8a9ea4)
- Use timestamp for sorting data [`0b23f4f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0b23f4f64854a27a7c486cd37afa0c8de49780bf)
- Update style.css [`ea2c482`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ea2c482832a1e7a01bba799025b15472c37461f1)
- Make providers list cleaner with white color for torrents [`5c4c084`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5c4c0849d2db1f8619f9622170d691a99df9aab8)
#### [v4.0.65](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.64...v4.0.65)
> 21 September 2015
- Add public-private var to providers [`#2548`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2548)
- Move exceptions to sickrage module [`#2529`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2529)
- Fix "Jump to Season* dropdrown [`#2543`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2543)
- Update t411 domain name [`#2544`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2544)
- Added WiKi to the config/info page. [`#2539`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2539)
- Finished lint of js files [`4036898`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/40368980f8d6e7cf071e2eb7adf6c0b29678988e)
- Move `ex` from `sickrage.helper.common` to `sickrage.helper.exceptions` [`e917a89`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e917a8999c24b5ba49f76cf3125e1e662aa499d5)
- Clear up some linting errors in name_parser [`52b837c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/52b837c7e1e49a88b67578a4f8448367a5580c3a)
- Fix undefined FULLHDWEBDL, make common.py lintable by fixing a few problems and disabling some lint checks [`a91513f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a91513fde738481ee43782fc15a4d460d09a236c)
- Change quality regex from hdtv to hd.?tv for source matching [`9ecaf25`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9ecaf2550f5b8938c233860c7e6b50199a6c83b1)
- Change imdb url in imdbPopular to akas.imdb.com (same as used in imdb lib) [`5639ab3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5639ab3056d48ab6c430d589e85784449a8b7d4e)
- Fix linting errors in logger.py [`c8a0df0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c8a0df06b74e64a8ec6648369a01c31239ec7b79)
- Remove leading slash from folders in gitignore [`1be19eb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1be19eb646181f427f897b44a21a696abdf32929)
- Open the selected season [`2f7b93c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f7b93c92d503b6c5b7f9173d1e5192e9e8ba525)
- Fix redefined class in mainDB.py [`9103354`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9103354b6ef14754f39b968ae915f9953f7b8742)
#### [v4.0.64](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.63...v4.0.64)
> 20 September 2015
- Make coming episodes results mutable [`#2538`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2538)
- Use full name of `showQueueScheduler` to delete a show [`#2537`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2537)
- Provider domain change [`#2531`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2531)
- Alpharatio does not respond to the SSL version [`#2532`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2532)
- changed domain name for NextGen provider. [`042362f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/042362fe4ccfd53e9137f9b92677d99efcda30da)
#### [v4.0.63](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.62...v4.0.63)
> 19 September 2015
- Add license info to all the files in the sickrage module [`#2525`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2525)
- Enhance quality pills [`#2528`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2528)
- Move encodingKludge to sickrage module [`#2522`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2522)
- Use common code to refresh a show [`#2521`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2521)
- Remove file [`#2520`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2520)
- Return exception as error message if deleting a show fails [`#2516`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2516)
- Add TransmitTheNet provider [`#2517`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2517)
- Use common code to pause/resume a show [`#2515`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2515)
- merge 2567 [`#2513`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2513)
- merge 2512 [`#2512`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2512)
- Use common code to delete a show [`5952418`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5952418a742bfbe66c89eb55466fd74ae7a1145c)
- Fix Confirmation Dialogue for removing shows and make class more unique [`e88c11f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e88c11fae04b6fca232df2b0cbcd21b84d4f4a3a)
- Fixes airdate on comingEpisodes [`7f9a2ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f9a2ca1198ccba839b7f4c4506a87126e3760f8)
#### [v4.0.62](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.61...v4.0.62)
> 18 September 2015
- Move "Coming episodes" logic into a dedicated class [`#2438`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2438)
- Only select required field in history [`#2506`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2506)
- Fixes https://github.com/SiCKRAGETV/sickrage-issues/issues/2774 [`#2502`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2502)
- BitSoup: Change searchURL to search_string [`#2498`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2498)
- Merge pull request #2502 from medariox/develop [`#2774`](https://github.com/SiCKRAGETV/sickrage-issues/issues/2774)
- Move home.js into file and remove show size column [`373aba4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/373aba468b14bfbe60a9c2ed7c1a11c730e76575)
- Changed home from fuzzydate to timeago [`d105605`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d1056059c94316352d760439d146e268f75c82b0)
- Moved comingEpisodes js to own file, added metas block to main [`027ae21`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/027ae212977e26d6782e1a32492e0d3e4368541a)
- Move "Coming episodes" logic into a dedicated class [Web UI] [`4f1a581`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4f1a581307e5b5d49c949e9fc87c9f66619a93a2)
- Fixes not showing dialog for removing shows [`23c1a61`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/23c1a61c0f2a3ff85279ee25e808828f05d67f4e)
- Fixes fuzzydates being used & fixes if checks in js [`83b2c69`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/83b2c69f9912b45a4314ecef081289189c42c00a)
- Remove use_imdb_popular setting, unnecessary [`ee01230`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ee01230a725a53b2dc296265ae4b94b843504c0a)
- Hide upgrade div on restart [`833a286`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/833a28636f88dc48b4f9dda6d28419adf801f779)
- Fix use_imdb_popular setting getting set to 0 [`91c4d09`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/91c4d098bfdbfd9d90801ac999d87f061baab43d)
- Hide git reset option in config/general since it is forced true [`9075788`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9075788d7785144646255ac63bb8c8f2365d7cb4)
- Change searchURL to search_string [`0055a42`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0055a42498e26043d5654d946e735ce8f9bf7bfa)
#### [v4.0.61](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.60...v4.0.61)
> 12 September 2015
- Fix typo [`#2490`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2490)
- Add Strike Provider [`#2488`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2488)
- merge #2485 [`#2485`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2485)
- Added missing Colors network logo [`#2481`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2481)
- Fixes viewlogs not keeping url state [`5dd4ecd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5dd4ecdb4aaaadf2c71edb67355203fc3a0a2296)
- Fixed bug in pickBestResult [`e65f319`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e65f319252637d4376aefff4b11b142baf75936e)
- Fixed bug in pickBestResult [`9d4506f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9d4506f5bc8df76c8a552e8e81eb42be6b49d8af)
- Remove size column js as it doesn't exist anymore. [`b81e36f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b81e36f150d102800dcb0a5325fd001bac72d608)
- Missed space in git submodule command [`35930ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/35930cae2364c6e33174976781dd5ecf340383eb)
#### [v4.0.60](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.59...v4.0.60)
> 11 September 2015
- Fix confirmation dialogues not showing. [`#2479`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2479)
- Fixed loading network logos when using custom data directory [`#2477`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2477)
- Fix HDT: use bs3 instead of bs4 [`#2478`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2478)
- Images are binary files [`#2475`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2475)
- Fix for https://github.com/SiCKRAGETV/sickrage-issues/issues/2719 [`#2474`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2474)
- Fix for blank options Deluge [`#2472`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2472)
- Trying to fix broken images [`#2473`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2473)
- Remove jQuery image loading and size checking [`a9d295d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a9d295d3a2fb8264106c84ede638df547e547850)
- Fix options for blank options. [`2132ef6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2132ef671a61b2c7f7c2ec9d94ba7c526e71f43e)
- hide size column [`30c4e0e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/30c4e0ed9419279ea463285a8540e396773e3f65)
- Removes size column [`b80fa42`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b80fa429ac13f3d8d13be1d21ef4212eb30dfc96)
- Change metadata message about not finding image to info [`a8c3828`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a8c3828ece5f88d8b096750e872586a4584e4992)
- Dont prefix imports with lib [`d810e9c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d810e9ca2913bf618f939dafec576d014b0bd99a)
- Don't erase cache folders backups like 'cache-20150910_190504/' [`c15e60a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c15e60a56c773d13dd774c903e2ad183cda44ffb)
#### [v4.0.59](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.58...v4.0.59)
> 9 September 2015
- Fixed Popular shows page title [`#2468`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2468)
- Show mako loading times for all [`#2466`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2466)
- Add temp log lines to HDT [`#2467`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2467)
- Fix header problem with torrent providers. Many need a real browser agent [`89d328b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/89d328bfd6603fa0595fb550c0f6bc79407297f7)
- Fix mako load times for all [`f15adac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f15adac877b6f4c7f434f734ecf6824e87675ddc)
#### [v4.0.58](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.57...v4.0.58)
> 9 September 2015
- Display "Add anime" after the anime table [`#2464`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2464)
- Bad indent maybe caused recursion depth error? [`9750a23`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9750a2390ca7d0fb21072938290399f4d38c0d07)
- Fix recursion depth error in _doLogin [`a4058bb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4058bb07ce7c38893d89edcf624e8293d36a067)
#### [v4.0.57](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.56...v4.0.57)
> 9 September 2015
- Fixes Page Title for Trending Shows [`#2462`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2462)
- Fix tntvillage match [`#2459`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2459)
- Restore support for relative, absolute and empty paths [`#2453`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2453)
- tntvillage: Fix torrents searching [`#2457`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2457)
- Remove show if no mapping (use addExisting then), pause dupe and remove tvrage show in case of dupe (move seasons from tvrage version into other manually and rescan before unpausing) [`28e007f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/28e007fb5cef4a0f8ae43ab224a9fb856013442c)
- Fixes massEdit [`edc4981`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/edc4981e73e1c47b5c2f7350a42c8bbe2ea2696e)
- Revert "tntvillage: Fix torrents searching" [`7afe253`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7afe253a4600b41215b82a83010e25959d5678f8)
#### [v4.0.56](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.55...v4.0.56)
> 8 September 2015
- Add tensiontorrent.com to removewords [`#2439`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2439)
- Add tensiontorrent to removewordlist [`#2436`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2436)
- Move logic to shutdown and restart SickRage into reusable classes [`#2429`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2429)
- Move history logic into a reusable class [`#2430`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2430)
- Fix images loading [`#2428`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2428)
- Shutdown/Restart have wrong reference [`#2423`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2423)
- Shutdown/Restart have wrong reference [`#2422`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2422)
- Fix SiCKRAGETV/sickrage-issues#2671 [`#2421`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2421)
- Move logic to load images (fanart/banner/poster/network logo) into reusable classes [`#2414`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2414)
- Fix for SiCKRAGETV/sickrage-issues#2578: Add a "Size" column on shows list [`#2356`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2356)
- Only keep /cache/images. Delete everything else... [`#2409`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2409)
- Override some jQuery-UI values [`#2405`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2405)
- Fix history limit [`#2401`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2401)
- Display debug data [`#2386`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2386)
- Added handling of seed ratio and high priority for new releases. [`#2400`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2400)
- Add support for non-ASCII chars in search string [`#2390`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2390)
- Fix for https://github.com/SiCKRAGETV/sickrage-issues/issues/2616 [`#2397`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2397)
- Fix for https://github.com/SiCKRAGETV/sickrage-issues/issues/2618 [`#2396`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2396)
- Remove failed status if feature not enabled [`#2391`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2391)
- Show "Add Anime" at the bottom of the anime tables [`#2389`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2389)
- Added missing spotweb.be provider icons. [`#2387`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2387)
- Added missing S4/C network logo [`#2385`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2385)
- Added missing network logos [`#2384`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2384)
- Fixed home [`5bfd5d9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5bfd5d9fa6b9e7a1afd819904347064d54a8f5ce)
- Move old files to views dir [`570e5a7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/570e5a7209916e528d70df0c27799a41ab8fb44e)
- Move logic to get show banner/fan art/network logo/poster into reusable classes [`6539420`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6539420dd15f758958f1a73f1448ef78c5f15418)
- autoflake [`7a4ffd5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7a4ffd519aebda2b09ead1fdc71a128a54b4e7b7)
- Move "Get history" action [`9dfa173`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9dfa173314c78790efb7404570cddb7ff013b76d)
- Update guessit to f7c067f161e3a937c972745a62321c73c8fa07bb [`ef4bbaa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ef4bbaa9bb2bd0b62f47d901471aee9044835148)
- restart_bare.mako isn't used [`0a0d1c2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a0d1c261df1575291bb9524c07479c03409a1a2)
- Update guessit to 0.11.0 commit 2516111ea7bf910df32d1b0c11a3e8e64490aaab [`f269f09`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f269f096c088bc06fe5dfd2e8ad66dcd06893b07)
- Dont allow setting to bare archived status, dont allow setting failed status in webapi if FDH is disabled. [`e56b434`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e56b434c40213a79afbdc4dd7edf5b8a9e5646ec)
- pylint doesnt like relative imports in __init__ [`b47de6c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b47de6c779c4a01c8f801445c205aaec665a85e6)
- Fix bug by gborri latest PR for removing shows with invalid ID. [`a65766d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a65766dc1dfa1df4e097cd7308e40d3ab772d706)
- Update guessit to 9c1e689b115bd641ffdb1dee69e0bfd0773f1d22 [`815a8e5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/815a8e5224d6eaab2ef7dc07f7074ed6936f7668)
- Update file size computation [`8d91331`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8d91331fdd81c78902b92d2f15640b9d32869c0e)
- Update sickrage.media.* classes [`20212e7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/20212e79156502d1ca3bae20ba746813eb957517)
- Fix some pylint errors in providers [`8a56a91`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a56a91d99d5eeb7b68f7146c14b22b5e81aa6e8)
- Fix image loading [`c1e24bd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c1e24bd7d02dc7a317024244bf13e45d49d564ad)
- Move "Clear history" action [`2e19f6a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2e19f6afa55003f0f3bb8376ce96fef6c4c525af)
- Remove my futile attempt for setting ca bundle path and sni checking. It doesnt work and pyflakes barfs [`01eedce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/01eedce1552bdd158b6ab261322ec10e45bfdb1b)
- Fix status column for shows in home.mako [`2f3d402`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f3d4029c80e28b9dd67c9ed0fcd8c84f9b2399a)
- Use get instead of refreshing the page [`70172a9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/70172a9e74c52121fb21fa1c3b773a35c2a0db1e)
- Missed imports, fixup conditions [`73b3c3e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/73b3c3e4d2d62b31cec07fdcdff76ab48723366d)
- Update jQuery and use cdn [`14d7136`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/14d71368d47d2b1551c7f0cd85662824db64dcab)
- Remove json selective import from sickbeard.browser, and make the getDrive cleaner [`ef02fe8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ef02fe8b6516755873001093cc188fc09b2bb793)
- Fix some undefined names, thanks flake8 [`616c209`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/616c20990f861483fb6c553f53a9b849b5e00a89)
- Oops, i broke that. [`e6a7521`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e6a7521e2bd3607b0acbbd4f256836b2ed667fc6)
- Fix metadata/generic and mede8er, not sure how these could have worked before [`6dac7b7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6dac7b7d614ce503b4dd523f900a0275d38da6b2)
- Remove 'freeze_support' since we dont compile EXE's anymore [`6cbe56e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6cbe56e156d84372e94a119e813e8db514aba699)
- Fix default sorted columns index [`7bcc79d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7bcc79ded6e51f8152dbc1c59d48bb88ad2303cb)
- Fix setting GObject in libnotify [`67c637f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/67c637ffdb8da6ffa19c89f2221c67ef12bec295)
- Last one? [`8715565`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8715565f66d3fb4d085eb290b499b4f14ed3fffa)
- Import fix [`dc55b73`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dc55b73be46d47b9c75285793ca30a9f3a8c90ce)
- Only cached imports work on the whole file [`37e0ea5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/37e0ea57c270586c853883767a400ed7d6e722ec)
- Revert "Only keep /cache/images. Delete everything else..." [`2c42cfc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2c42cfc05bb70f80d9b37d4923f387d855bdba4e)
- Fix Boxcar test notification [`9b017ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9b017ba090abec59e01cd0889c560583cbdb04a2)
- Fix twitter DM notifier [`67f62d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/67f62d703c84d1a1cf800fe53b58b621ace1c004)
- Fix for PP not moving subtitles [`17bb919`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/17bb9194713d8a7709d3987d97ff40f460328cf9)
- Fix undefined in webserve.py [`ebb4ddb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ebb4ddb354682edff3eaee596c9e661f6be0ac2d)
- Fix typo that prevents sound from saving [`a6a3f89`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a6a3f89af5cf8930e22677b15087fb96246edaeb)
- Bug in emby notifier [`84b9933`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/84b993356e23227bfe646d2cc6998844771c89b4)
- Remove archived [`41db28c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/41db28c00ae28a1f05c98165c0167723c0e2077f)
- Missed sort var [`207720a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/207720a6c78fee677652612836441dc35a9b351f)
#### [v4.0.55](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.54...v4.0.55)
> 31 August 2015
- Add ".[BT]" to removewordlist [`#2381`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2381)
- Add missing jQuery-UI sortable widget [`#2379`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2379)
- Update dependencies and use minified resources [`#2375`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2375)
- CSS optimizations [`#2372`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2372)
- Display episodes list of collapsed season when select all is checked [`#2371`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2371)
- Fix CSS after #2336 [`#2370`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2370)
- Sort the appropriate value in the "Downloads" column [`#2368`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2368)
- Added missing Yorin network logo [`#2364`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2364)
- Remove duplicate CSS rules [`#2336`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2336)
- Fix for SiCKRAGETV/sickrage-issues#2498: Include a print "Shows list" feature [`#2335`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2335)
- Crackle network logo update [`#2355`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2355)
- Fixed up deluge daemon handling of torrents that are already added. [`#2353`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2353)
- Remove unused files [`79e0094`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/79e0094ffd0dfd2c84ecc29b2ce70d9af47db816)
- Use minified version of Bootstrap and remove unminified version [`fcf5486`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fcf548626e68feac0eb82ff4adc1cf947aedfece)
- Update guessit to f25e1b30c60f334ad378d1146a900797e8f76240 [`bae9b15`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bae9b15afa3c44e5ecaf10c99c771f1c92e4de9b)
- Use minified version of jQuery-UI [`3201494`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3201494eea100404cba272c7b124c53995938028)
- Remove obsolete Google Code and Windows binary distributions [`b2ee3a6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b2ee3a6b1ec771b0d4a796dd7bb6e857b7ae80af)
- Update Bootstrap to 3.3.5 [`44a16e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/44a16e45756a9475472224906b8ea5678ad7d4ed)
- Remove trailing spaces [`8e552e6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8e552e612853c95960a09693837e46124d5d218d)
- Render more specific quality pills on show list [`8e7d7a1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8e7d7a156e113fcec700e9d1606de2ac240f70a9)
- Fix menu icons [`9f6339d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9f6339da8f39c9f91acfdd9db2880ac211176ef5)
- Remove duplicated rules [`30ba6a9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/30ba6a97d2d88d0255a4ae7041fa35f8ada0fa18)
- Cleanup on silly call in most providers [`9f4558c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9f4558cbeacee833cbc29d13b3b70529e391e426)
- Use show_queue to remove shows [`5911672`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5911672e5f3ea74dfffa985cdf166daf619470c1)
- Remove show from trakt watchlist that are not on tvdb [`2e1a576`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2e1a576df84340a588cd196fc4bc4d7f34f62ccb)
- Re-apply x265 patch, so they don't get detected as unknown [`66d5700`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/66d5700844dba0afc9f27795b8bbe6b8419c01ea)
- Remove from trakt right in the queue item, as there were multiple places shows could be removed and they werent removed from trakt. [`afe5252`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/afe5252cd52d6fd49ca3f29db943e95b5b8898e1)
- Load images after page finishes [`b9533f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9533f1a6cfeda7b607f4f8bc784919f20262cf3)
- Fix progress style [`c0e7900`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c0e7900fe4d256c6ea2e817fff3e5cff9ab627b8)
- Fixes 80 - 100 always being set as 100 [`cbd0948`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cbd09480cc4a4a72c0b904e1714d61004baacc4d)
- Fixes progressbar sorting [`3d2f382`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3d2f382c1423e3ac5d06c30e88ea6a6813d6272d)
- Fix file permissions [`1b1e387`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1b1e38783ed200f27c9765edb8ba52be955844cf)
#### [v4.0.54](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.53...v4.0.54)
> 25 August 2015
- Added Vimeo network logo. [`#2341`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2341)
- Added icon for Xbox Video [`#2327`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2327)
- Dont allow forcing daily/backlog search on startup [`e1e3cb2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e1e3cb2368b0d99bb29476ad40a8273cb1245f3b)
- Modified deluged_client.py to allow move to folder to be set. [`2686562`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/26865623e799aada4e294d0cd6d72e545673a1de)
- Revert "Fix bugs when using banner or small poster view with cache images" [`4b97901`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4b9790173a132f4485c0c30d0265d87c6ad02a86)
- Fix bugs when using banner or small poster view with cache images [`89c9bbf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/89c9bbfa0799cfb3a7bba054db799b579ee1774d)
- Let tornado handle etags for browser caching~ [`eaec6c8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eaec6c8a426ed147ef49915f3f6d55362823b009)
- Make posters and network logos permanent redirects so they cache browser-side [`2cb7667`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2cb7667fc1865a1578e85466bd021f16856a0340)
- Remove raise from newznab. Change to ERROR [`5ac5073`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ac50733382995128bd2e1dca3821697ee5c1aab)
#### [v4.0.53](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.52...v4.0.53)
> 19 August 2015
- status command should not always return 0 [`#2325`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2325)
- Add ".Renc" to removewordlist [`#2319`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2319)
- Update imdbpy to 5.1dev20150705 [`06c2fbf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/06c2fbf46143d464c16f2ec80cae796d76dff9ea)
- Remove update on start and update on snatch options, always update on boot, to prepare for new api show updating [`4d56699`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d56699742abac74a7e8168d38a7c1f1bb844a9e)
- Fix commit hash in updater [`2034443`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2034443f36c11a7abf927bbd5e4fca4694883516)
- Remove branchdest from getDBcompare [`4238c5d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4238c5d7a845fe57e9cb01dee7694b55ad856824)
- Fix issue getDBcompare() takes exactly 1 argument (2 given) [`06b9304`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/06b9304cebc84e978f6a92ddde99813b1ffe5c67)
- Fix broken debug checkbox [`919b69c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/919b69caf5427f39595988487df78b00baea4487)
- Fixes error when saving config [`2c4bfe4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2c4bfe44c0f9a37533cfdaea3dc28fdb85cf2e4b)
- Fixes error when saving config [`79fb5aa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/79fb5aa3322236b22286619cf7028f6cafb3a1a6)
#### [v4.0.52](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.51...v4.0.52)
> 17 August 2015
- Cheetah > Mako [`2945d7b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2945d7bcb8f0ab4586ceae575f082cb9ab0945ed)
- Fix homepage with fuzzydate [`ac28f04`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ac28f04070ac131fbfd52a1887ad297e84bb6037)
#### [v4.0.51](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.50...v4.0.51)
> 16 August 2015
- Added missing NFL Network logo. [`#2309`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2309)
- Add "Amazon Prime Instant Video" network image [`#2305`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2305)
- Added missing network logos. [`#2298`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2298)
- FIX: Subtitles Extra Scripts [`#2297`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2297)
- Add new Deluge Daemon Client [`#2300`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2300)
- Adding a new step to make sure that develop is up to date. [`#2286`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2286)
- Fix version checker ssl error [`#2278`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2278)
- Added support for support HEVC (x265) [`#2283`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2283)
- Mako [`#2222`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2222)
- Reset templates [`c1e994c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c1e994c826374f4fc1a9f1ace2eb39436f184453)
- Update hachoir libs [`04b138c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/04b138cdc6f0cebcc644bf529a24eda2782ea701)
- Re-apply patched mako templates [`5fee0b0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5fee0b0d46ac4dc111856caee6c36960267186b1)
- Fix js in all mako templates [`1f90988`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f90988f4bb1970b8d661b641048f05b4793578f)
- fix much missed conversions, use bool in true/false tuple index [`bea805b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bea805bd0d25f45ba6b97cfa95ae461b6cdf58fb)
- use bool for checkbox tuples also [`b5355f7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b5355f721b127c6ac41a9146dd0c312f40adf8b2)
- ___ [`d42f96b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d42f96b8f321521bbd027e7d3c554201f0fba2e5)
- Working on status [`aa2a137`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aa2a137f274434c72c78146f5e83371b23d597d2)
- config_notifications done [`f0842ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f0842ca2578faa85ef208010ce0d26100749cf6c)
- Mako version of imdb_popular feature [`9e4a29f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e4a29f3a4e61f22c4ec81737996b2a4cc39d0ab)
- Remove animezb.com provider, domain up for sale [`4d81b19`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d81b19e7ca5627c44712aaa19ede5560b532c05)
- Mako conversion of webserve.py [`dabd08f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dabd08f07cd90c45d784a466047fab65eace07c4)
- Normalize more true/false indexed tuples, fix a few out of order [`90503bb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90503bb8d8318ca08460048e3b3a6a7419389549)
- manage and manage_massedit [`c72db16`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c72db163e9305fa168a027a55c0011c50d5ad3ea)
- manage and manage_massedit [`c51c322`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c51c3220bda85a9e81a229f89da6fabbb2969851)
- status done [`5a77163`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5a77163dfe747fbe235f7523dee1ebadb8d21790)
- config_postProcessing done [`18612e9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/18612e94ceb0a8e1a16742fb314ac8af242af34b)
- Fix column selectors, progress bars, help&info page, small poster layout [`6ffa72f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6ffa72f0c1eee4379f9272ac59a66c1cb83b485c)
- manage done [`89bd797`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/89bd7974ddb3c814f75175f5a3c14e77edf96542)
- Fall back to using video height to guess a video quality if video is not in snatch history and quality cannot be found from file name [`5ef77b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ef77b35fa935ff8fa1c5f2dfbf115de15d9344a)
- config_general almost done [`fade1a8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fade1a8f1002ac6a3b258fcca6fec88e09664567)
- Update pynma to 1.0 [`0285f4d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0285f4dffb7b64cef72e4e3ae43f00c79d510ccf)
- Update pynma to 1.0 [`4f4bb47`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4f4bb478c8be0087823221375521a91899049649)
- Fix history page for mako [`4e59a8e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4e59a8e9857ec81a47b46b164c7a24acc1596945)
- manage and backlog [`1a0c299`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1a0c299d44d9c9b67b402d13005c2d54cffbf485)
- most of config is done [`2bd744c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2bd744cdf24391dbde66a764d1375bfb5498a04c)
- too tired to finish [`8dbda68`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8dbda682a8c7b91a77ac473f110fe20d7717b079)
- manage_backlogOverview, manage_failedDownloads and comingEpisodes done? [`174ce67`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/174ce675c4a46501de65a0b254d832cfe2796fef)
- manage_backlogOverview, manage_failedDownloads and comingEpisodes done? [`3c0ef08`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c0ef086015892e900314c409ae056e615359bf0)
- config_providers and config_search done [`ea2418a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ea2418aaa1071d17e1666c4220aff1a7da2c8405)
- manage_backlogOverview [`19d8005`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/19d800588c99db1e8e88f2986335ea3b8e73e592)
- manage_backlogOverview [`b7c2a71`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b7c2a713a54ea3b690564bd6e6187c489562216c)
- Fix config/postProcessing and genericMessage [`2647466`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/26474664b746159368237072841c55c40b8371ec)
- config_subtitles [`0308427`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0308427daf61326ca95ca73f1cbbc3bb524d5ff0)
- new style imports in sickbeard/__init__.py [`5c0ed9a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5c0ed9af9a59cd0517ed6956d00952a9b029065d)
- More fix for preview rename [`f03a513`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f03a513869c8a0cfa36b227f571009cc2982bc0e)
- Fix all sbRoot/sbPID [`e794c64`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e794c6497511fd9990730ff040b3ce08eb2b9a44)
- Fix edit show [`52ef491`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/52ef491757a6c780e5a6bee8e9a34af8848a1654)
- comingEpisodes done [`2d9688b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2d9688b71c1676f7f14a627afde4ede443f68a63)
- More bool for tuple index [`a6932bf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a6932bf3fbde2399816c56f8d723747bc59afc60)
- Fix addExisting, snatched count in footer, and curDelete in manage [`91a37e7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/91a37e7a9b059237b86d6ee7b15248b8c2174cba)
- Corrected faulty filesystem freespace check on non-Windows [`4903979`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/49039790513a24a4206fd03d1414379fd0c584e1)
- config_general pt1 [`e0397ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0397bab31e570ae35da554c0f96d3984bc73072)
- Fixing typo recepients > recipients [`8fe33f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8fe33f1af3fa1d07fe753ef418146de945dda2de)
- No need to check for mako, it's in lib/, bump python check to 2.7 [`b6be881`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b6be881fd3b3a3aafc499b137f8bd56908c7bf9e)
- Cleanup [`532baf6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/532baf6e0805ba419c9bb235be41d55c9dddc2de)
- history fix for } char [`108919e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/108919ee1854d6191d8e679ea1ec0362892d548e)
- history fix for } char [`aaefe3b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aaefe3b33df3f509365aa9287243ce80d66ab767)
- backupandrestore done but needs imports touched [`5076608`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/50766080d765c4732b6c7afc6906dc122d49bf2a)
- Quality chooser fix [`1673b7d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1673b7d6e2508e7a171ff6fe9e03f94c3c636528)
- fixes subtitle page not showing selected subtitles [`c6b6224`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c6b6224ac931fa6dc1c91b35d750f4c4d5845fb8)
- User iteritems instead of items [`4f6171c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4f6171c7cfc4978c6a7ae191962731575fbfdc9e)
- General and backlog done [`a4f060c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4f060c2c7b8256dc20acf7f2341138b0be82c17)
- Fix backlog overview [`0b0d381`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0b0d38134cb7ad971ffe394d31d189f31ce8f678)
- Fix coming episodes [`1255579`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/125557921a7e1fcfcb1029674a816bcb43cdcb84)
- http instead of https for rarbg torrentapi [`60238b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/60238b25ba29708a71fe3813a4abbe352d6511ca)
- subtitleMissed done [`8bd54f2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8bd54f201431a66d2098c3657dbda5c921a23b67)
- subtitleMissed done [`bfee64a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bfee64a2ddb63f3bf8aa850d6293a04a136fcc22)
- Fix exception when obj is null in generating meta images [`f58bc28`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f58bc28189fc7aa54f1262da6f9557285a742900)
- tmpl -> mako reference [`9bab171`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9bab171ff279f2022a3c763192183e8c26da2d17)
- managesearches done [`dfd3798`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dfd3798ced66b894a4c0e530dda4ba029bc45e74)
- comingEpisodes and manage_backlogOverview done? [`5d4995b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5d4995b9ff95c56c957a57d43120a5363224106e)
- managesearches done [`ac5e11c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ac5e11ca14eddb0edba286211d59a615ca435d02)
- comingEpisodes and manage_backlogOverview done? [`1f4f5e7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f4f5e7f990e5c1093bc7bfcaf32666c81f523d5)
- Fix mako apibuilder [`2a298dc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2a298dc8a35de06b71ae60dff0397ec212165586)
- Revert "Moved closing div tag to fix layout issue when a show doesn't have any seasons" [`43ac198`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/43ac1981f1de32354478d498e752cb00ee84f3e0)
- Moved closing div tag to fix layout issue when a show doesn't have any seasons [`6c0071c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6c0071cf8e06b6b080897458cba6415ef40970be)
- Fix mako compile error not recognizing backslash as new line filter [`8155d40`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8155d40eab485c72f2bc1cb1f7c67ac6829d1972)
- Fix not being able to enable/disable subtitles/flat folders in edit show [`c4916f2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c4916f2e65d47e5ef7101b1637c8656907960410)
- Fix for double dropdown date style selection [`937c095`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/937c0951dd1dfd5aec353905460b51bfa48025bb)
- Reversed active/inactive images on home page [`bf48058`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bf48058420d7339d24a4f58dc47c1d6cadaec2c4)
- Fix manage_subtitleMissed [`6d9df4e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6d9df4e344d91506a7f2c5d6d228bfe9ae307c70)
- Fixes syntax highlighting in editor [`7fa2765`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7fa27656238f4eeafcf8dec871841e9994531951)
- Fix loglevel and logfilter dropdowns in viewlogs [`fba2943`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fba294395ebcee645a287573a8d1bdab7808ceaf)
- Remove trailing '/' from torrent path because some clients don't like it [`b27b7ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b27b7ba5337151dd88c4db77facb7f84b3a13df8)
- Fix login page on mako [`ad226c5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ad226c51a10a56e5c69bea9b9e8f0316cce75f70)
- Header and title for test rename -> Preview Rename [`9ec727a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9ec727a00be94146e96061a42791e8ef6c3d0338)
- Fix history -1 and fail img [`4fdb8fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4fdb8fe41069029656d3584a1bcfb2eaaca15622)
- test rename fix [`d3c2057`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d3c2057008f6132158bcd0a9333888005e02eb47)
- Nofolow for robots [`abd7d9f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/abd7d9ffce60195c175b7f91fee989b27fced618)
- Update Wiki URL [`6a545ff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6a545ff45d808180569b5718ce58fbf593f33307)
- Update wiki URL in PP [`992c82f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/992c82ffb1ecb175bbf96a0c692d7cca6f56cdb1)
- Wrong variable name for setting attrs in newznab [`19d19c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/19d19c4ac68a76975b84694956edb8d423f7e1e0)
- Rev [`360bb2d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/360bb2db72b5a169aa34f3822874816db677c7bf)
- match fix for subtitle providers [`8f35907`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8f359078037f7273679b33fb25c2f5fcce47d6e5)
- Fixed banner issue on comingEpisodes [`111b4fc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/111b4fce6e51c7c0b1d543f7f7116cf85acda144)
- Rev [`bbaac56`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bbaac5603d4b99842e9141f1501594cad7d33b38)
- match fix for subtitle providers [`29adce0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/29adce0c288c7ab9d3507aa714186e5dcf933a55)
- Fixed banner issue on comingEpisodes [`e1bf8f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e1bf8f1b0fc54c972914ddc149b13563f14006b8)
- errorlogs done [`5344697`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5344697bb10cd5ad413cf3f490e1c1302adbedb9)
- Missed $, need to go over this as I don't know the url to test the page [`a1bfabf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a1bfabfa162596a9eed5d1d1b4ee515a23ba5b87)
- Missed $, need to go over this as I don't know the url to test the page [`6136fad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6136fad9a0a4bff759bd2ad4cd87496d071b1295)
- sickbeard.layout in 'poster' fix [`a967db2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a967db21e104476b1a809b949aed63759520e059)
- Missed t. removal [`e6fe095`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e6fe095d0d9ea8fb65c81d0b240a86e58824b64e)
- Rename tmpl to mako [`c5a7b6a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c5a7b6a7904704ca873494a9348e16cd8aaf4546)
- Merge develop, breaks inc_top [`9f1004d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9f1004dd944f958d7e96d90fb8772fe172328b62)
- Create all .mako files [`08343e7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08343e7e0ee2791b877b91316e8e13dfa6b1049e)
- Replace tabs with spaces and trim trailing in templates [`6c5fe55`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6c5fe553a8d84b1fd5053e7e53db755255b03ec4)
- Removed some tmpl files thatve got "working" mako files [`7a6a090`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7a6a0902dddc45e92c00325b7ef70a57c9c6888c)
- comingEpisodes mako pt3 [`e920212`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e920212af5d416f0111fa99500cea996af9d25ae)
- config_providers mako [`2ba561c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2ba561cef11f33028e3737eb056be8a815a5f9c0)
- Don't break it again [`b0df89b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0df89b4ec8537790a4b0a43bc66360f0d0b2b16)
- Oops?? [`ded3fbf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ded3fbf07059637cde652129fc8b31ed161d0d4b)
- comingEpisodes mako [`9008b45`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9008b45936fdba67853d16364dc034cb6e80811e)
- Removed unneeded tmpl & fixed config mako [`9d5bb95`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9d5bb953802f7e8d5f5e6527eaba82a359eef163)
- Create apiBuilder.mako [`ef8dd99`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ef8dd99ef7a9a8dcd498b8d615e5f0be309cbd74)
- manage mako [`9dfc4a3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9dfc4a3a996081f504f60ab52a62e75faf795189)
- home mako pt2 [`7af4dc6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7af4dc60949704033741d8ef9be922feaf64a5bc)
- status mako [`ec69683`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ec696834c5f6dcb7af67588cea07e600cfd56451)
- Removed inc_top.tmpl [`2928016`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2928016c9f6cb5c67685b52e2d4bada3ea0c2087)
- Convert most of inc_top.mako [`bbccc38`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bbccc38ebbe3baa288d0fe698a75419ec5dcb508)
- Convert most of inc_top.mako [`08ea0ec`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08ea0ec030c64b2a479604747e4f7016c14d7a57)
- config_providers and config_subtitles mako [`549d685`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/549d6859f0ddf35362a53e2d0bec250f417debec)
- Fixup home.mako [`15d60fd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15d60fdb1f45eccd2af6a204c0e2f1be76b4cc07)
- removed more tmpls [`35a4cb0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/35a4cb0a0f65c8ed4070852f16a857a28063c112)
- home mako pt3 [`6935dad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6935dada2738d5201ed99ef055cb04bff74dc2fd)
- home mako pt1 [`b2285f8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b2285f81768758fe8da57ff752e77424d7fe7226)
- config_search mako [`48ab1d2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/48ab1d2a97a169ecbb65a116434b616a0fd1d32f)
- history mako [`1a58060`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1a580608dddfe4fbff4fd3669e97c596a97ada38)
- config_search pt2 [`73c7416`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/73c74163a11d88a44e6bbafc3a83aea72045ff08)
- config_general mako pt2 [`cacac7a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cacac7aa3a0390bccb3f50096ddaca127452436a)
- manage_subtitleMissed mako [`a47c3a5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a47c3a5e7149cfd208b1090afb9029ac9cb1b070)
- config_providers mako pt1 [`c1077a0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c1077a04b9bbdd6a33b88be2a9fcfa563488ccc2)
- config_general mako pt1 [`e544ddf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e544ddf877c65942d2aebece55bfe83fe18a34a4)
- Convert apiBuilder.mako to Mako [`ee03e01`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ee03e01f6bbda5182cf69935d99751036aeb1f2b)
- manage_backlogOverview mako [`b872e2c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b872e2cde9b8f0c535c0ed667e512474dc5ec01e)
- Removed tmpl and markdown mako [`a4dbb8f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4dbb8f06b8ae44609f3ddaba3c8e350bd00ccfd)
- manage_massEdit mako [`0a078d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a078d7acb4326ae0a35268d888016cbd585ac49)
- Config fix and postprocessing pt1 [`dc1edb1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dc1edb1ca4eaeac0618f7a19f4ea52fbc1bdae18)
- config_notifications mako pt1 [`844de1e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/844de1eff98c33bb5a82692c9f1fcf2c34fbd70a)
- webserve semi-working for mako [`a04ffa2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a04ffa2fa7ffacc091570d78db87799fc438b595)
- inc_bottom mako [`e5a60af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e5a60af92d6e1d61fdb02cf0997fb3c9cf13f30e)
- comingEpisodes mako pt4 [`5e2f443`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e2f443a170e17d0bfedb02969afc628411a1fe0)
- comingEpisodes mako just needs if statments fixed [`db28612`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/db286128c09feca29e90706289071869d81e7b33)
- Don't need config.tmpl [`e4b756a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e4b756a14d5990732e620eb02fa7de73a132a98b)
- inc_qualityChooser mako and tmpl removed [`56548c9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/56548c96366c18301a54c40318dd29af4e272a97)
- home mako [`3360b5d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3360b5dd8fe3749276eb2b809d3fe27a40651363)
- errorlogs mako [`8403651`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8403651fc7786def2f1fd27c6d9b46cf5863e088)
- manage_failedDownloads mako [`659ce46`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/659ce46ae924f2ea8ced397806829fc930902b79)
- config mako [`035501a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/035501aec00a3f53e9f0cbd378346b2bd01dde4f)
- postProcessing mako pt2 [`9b5e881`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9b5e881c65230db07221a01730205447e440471b)
- config_general mako pt3 [`2792629`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2792629e370fe3bab35e64835abd8c45536c436a)
- viewlogs mako [`e5546a9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e5546a9a4ee5b1b486a6f7528336fa5fc367bfbb)
- config_backuprestore mako [`8244ebc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8244ebc8a2e5dc56dbf076da4bbcf04c7d589836)
- More mako [`9d92840`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9d92840c8da6cb049b1d8c1b28ec338f6117a56d)
- More mako [`8ba2301`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8ba2301af82c5003d3989f48391eb0f0b8636354)
- config_general should be done [`1606e94`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1606e9415abcf4a0c94817149b6d06bad009cab8)
- home_postprocess mako [`d8655ea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d8655ea92966628e70daed849bb14cd0edf4c74b)
- restart_bare make [`624dfcf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/624dfcf05dee5d4128a40126fa635e7c0b9100ee)
- config_general mako pt5 [`e3e79d8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e3e79d849419ef032352c1b2f9aece6656d7d4f1)
- config_anime mako [`e20cb96`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e20cb96c0d3c6ff98d737ddbddae529422d9400c)
- config mako pt3 [`4348f6f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4348f6f8d429237f79ec97a5428cc7a28795f929)
- manage_torrents mako [`fc4abba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fc4abba822f9f42ac9a07f0be82a3745434022f8)
- comingEpisodes pt1 [`ac93418`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ac93418169f59735537649b4348d6d2c6f90be1e)
- history mako [`feaa50e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/feaa50e515f886beb0a2a3f6abf0a642e533130e)
- inc_rootDirs mako [`9a56e97`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9a56e9722b20022c84fd61cdf1303e8f3a6869ad)
- Inherit inc_top, include inc_bottom [`6945832`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/694583288a3eacbf000430dc1e229f985dc4d550)
- comingEpisodes should be done [`45948a6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/45948a64937443345198c335e5244c455643c7ad)
- Don't import tmpl as they should be removed [`4ed23e9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4ed23e9abb84d467afe2d441daa5387f9c24c0da)
- broken mako [`22b9575`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22b9575e309ab23a9139a8aea38621510ff7e259)
- restart mako [`088cf97`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/088cf971b34db69eef6a96cb90473579f511c08c)
- config_notifications mako pt2 [`cbe7688`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cbe7688b504227786ea4715e7e177a2459a996cc)
- history should be done [`d604a3e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d604a3e7c38702bde23bea2ac3ce8625559a076d)
- Yawn [`26a4c95`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/26a4c9596e7bccfc352a4e774b7b7a3f63a7c466)
- swapped ifs [`10bbe99`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/10bbe99609f8a994c83f3edbc84bf54084ddfe1f)
- IRC mako [`9b9eafd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9b9eafd16ccf3f82a429b9603710772f6d050f0c)
- Finish apibuilder conversion to mako [`3003dbd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3003dbda8c75a420208b255b1ba0fe3a32a106de)
- config_anime should be done [`8737d2d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8737d2da1c7378dbd450998d109a063fb587c04f)
- inc_bottom should be done [`053afa3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/053afa321b5c978ccc7f5e88c189ccaebcf3f13f)
- genericMessage mako [`c53eecd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c53eecde7d9f2aaf14377249fcd0e1e601afdf8f)
- swapped ifs [`75159a5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/75159a5a06c5d4b56a7c8a43fc171c483fc1c5a0)
- login mako [`221de9b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/221de9b8a127646657fd8e4745fbc7efd7cbdcf6)
- config_general mako pt4 [`5cd1092`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5cd109211011eca56304c96c42def35d5a0e9dbe)
- config_postProcessing mako pt3 [`a70f0af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a70f0af027013c8edac2832d0b71892f86a345bd)
- home should be done [`fe6a553`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fe6a553207b358463d53cbba61e75f1dbfac5460)
- Header exists mako fix [`e7449c8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e7449c8dc14148049ac09a65a85997ced069fe88)
- Let's hope they're meant to go there [`981965a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/981965ac18901a99c8051965cbef0e474a992690)
- config_backuprestore should be done [`deb66e5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/deb66e542ca63e478f3a177e3f684a27a84d10f7)
- apiBuilder should be done [`3d52c3a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3d52c3ae6fc2b300c65f2fe35fbb2eee4c87dd65)
- fixes L269 weird line on inc_top [`463c579`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/463c5796a61828cb02a3bfa6abc66477488f8afe)
- inc_top mako [`2a4ad7e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2a4ad7e3f556ebcfa465cb5fa6cebf3ec3f67cf0)
- Fixed missing $ [`d1af927`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d1af9279faaf1c4cb7c176e132aa2cd83f799529)
- Change requirements.txt to install mako, change readme to say mako [`b08fb91`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b08fb914d6fc8135976415b92952a46dda513728)
- swapped ifs [`0e285ef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0e285ef0197792e2542f364f6a26d04a40020942)
- IRC should be done [`292ce21`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/292ce21546bf1cac72e9266e36e29a2add7e1b0e)
- history using mako imports [`e94abde`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e94abde340c5dcb7ef5144b8a290caef6dddb916)
- Forgot a few # from home [`960cf87`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/960cf872b38b80a431bb67628e7aa7af6098e648)
- Removed #> [`b754a67`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b754a67f3a379b350cc18482bc030264d6b9960f)
- inc_top should be done [`c43e1a9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c43e1a9555931ed1569df09c8b91bbc3ffb1bd4d)
- Fixed merge? [`4ce1955`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4ce1955bae414a07b59f4a34f399848b436dae9e)
#### [v4.0.50](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.49...v4.0.50)
> 5 August 2015
- Changed name of provider icon abbeygirl.co.uk to new anonzbs.com. [`#2270`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2270)
- -Siklopentan to removewordslist [`#2266`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2266)
- Add [1044] [`#2251`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2251)
- Newznab: Only have rid in first query, no string query when rid search, and skip string queries if rid search had results [`89f2ce3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/89f2ce3c7f2271eb5d35b4dbfd99a1d5ed5a1efa)
- Newznab: Only have rid in first query, no string query when rid search, and skip string queries if rid search had results [`8abd29b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8abd29b2968b240990cae4c65cdddf8dad1bd01d)
- Fixing indentation on emby notifier [`df4adf4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/df4adf4d5525e5f30261f76e46e0056c212e35de)
- Fixing indentation on emby notifier [`5199c07`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5199c07b4ea632b60e6cfe9d2a2eaf254991ef23)
- Display show/episode which image was unable to download [`2447776`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2447776983a8bd3414d6aae8a168c4f7932e8e75)
- Don't accept results for episodes that have not aired yet [`732fb5b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/732fb5b39ce3b89fafed6d5e7fdf3269cb43eb26)
- Don't accept results for episodes that have not aired yet [`b0e2a99`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0e2a99dba760b0f04aeb5110babeddcd100645e)
- Missing session for nzbsplitter [`47b2d56`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/47b2d5651f0c7ef1d8d20523dee85bc950d17e14)
- Missing session for nzbsplitter [`2075b54`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2075b546cd4cd252d7a25aceaf55e9d59f5a856a)
- [1044] [`ffd1d74`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ffd1d740230f30d023dbf9f594d7e2c92ea64b61)
- Change PLEX Identifier to user agent [`3c2e42d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c2e42da647e6dc52be0c0ec2ce8fcc9d3b3aff7)
#### [v4.0.49](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.48...v4.0.49)
> 1 August 2015
- Change 'unable to obtain cookie' to warning messages [`#2231`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2231)
- Added Piratennzb provider icon. [`#2243`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2243)
- Add Emby notifications [`#2237`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2237)
- Paused Shows are Showing in webapi Backlog Query [`#2236`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2236)
- Add variable in init.fedora to allow changing the Python path [`#2230`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2230)
- Replace tabs with spaces in templates [`11bd12f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/11bd12f7d0d3d6c99026590cd844bed566cde874)
- Update guessit to 15bb35b885b94c6494fbfbdf872890d0717dfabf [`b387dc9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b387dc9741697259d87abd3ffb741522fc4ed68d)
- Can't do a season pack search in manual search [`97b1469`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/97b1469441a113b8007172d88be532b2ed6799c0)
- Fix equality vs identity problem in catching requests status codes for trakt [`8fa7a4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8fa7a4bb777c9192bd706115579e540eed8461b2)
- Fix equality vs identity problem in catching requests status codes for trakt [`7227f4a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7227f4a101ef5fc8abb6f326aaf77dd963cc1a03)
- Fix thread naming not showing up [`6cba297`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6cba2974684ea5663b748a9b4c5606ddbbef7545)
- Update torrentday.py [`64b6bb4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/64b6bb40907bd57a0fcafc893d16f69de8ce8406)
- Only email committer if build fails in travis [`ec0a811`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ec0a8119b194b76ea5df5dfcb608d724739e0a12)
- Fix missing " [`051c99c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/051c99c5773d1b824b18227ffcc02d8f80112d17)
- Change time out error to warning [`be8026b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/be8026b8cc7148a5c3dd6024a3671113fb6415d4)
- Dont fix episode status for special episodes [`23b3a18`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/23b3a183e4705d8be35b8340f78178514d0e631f)
#### [v4.0.48](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.47...v4.0.48)
> 29 July 2015
- Check if SR is updated before submitting an issue [`#2217`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2217)
- Replace tabs with spaces in templates [`0db61e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0db61e2eb4fcd4ab7556950b436759e6876fe205)
- Update guessit to 15bb35b885b94c6494fbfbdf872890d0717dfabf [`0d651b0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0d651b0b3388e073d21da8139f833afbe0ef7182)
- Need to make sure data is big enough before decompressing [`7b8963e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b8963edfd7dc9f02fe52e7433620c24168123f1)
- Dont fix episode status for special episodes [`eea739f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eea739fc4f6ea527be5e817389b3345f108d159a)
#### [v4.0.47](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.46...v4.0.47)
> 27 July 2015
- Revert text factory to may19, until we can fix unicode [`455568e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/455568e4abff0952f1507e6a3f31b622962a89bd)
- Missed a bad return [`c3ec79a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c3ec79a9423342abe1601591960e0e34f636068c)
#### [v4.0.46](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.45...v4.0.46)
> 27 July 2015
- Fix Xem refresh [`#2208`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2208)
- Show skipped files in log INFO, not DEBUG [`#2207`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2207)
- Added missing provider icons. [`#2205`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2205)
- fix xthor crash (ratio) [`#2203`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2203)
- Fix for SiCKRAGETV/sickrage-issues#2337 [`#2200`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2200)
- Remove headURL and see how it works out. bt-cache sites are only necessary for blackhole now [`02f14a6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/02f14a655f11ed0e5ab12d6183683f2ef3e56ff0)
- Cleanup hdtorrents a bit and fix a small bug [`558068c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/558068cd30e9f8dcdff026e56ca86fe37a993512)
- Fix returns in xthor and ftdb [`f3f0efc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f3f0efc39fb8e4278df737b6671f7cbd554f5e95)
- Don't search eponly in sponly mode, just gives errors about it not being a valid season pack [`57e3173`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/57e3173e9ee8bf7efc009a5c801cd93ef12c4391)
- Use issues even if they are closed for issue submitter [`6831ae9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6831ae9131af765586c1d348cc1835f363f350ce)
- Use issues even if they are closed for issue submitter [`0896d49`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0896d49895262e5ae6a7c991f4a7af8d312e456d)
- Fix bug preventing torrents with 0 leechers from being downloaded [`8f6f619`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8f6f619538d48af1c3429f2a2109b47fa737c5a7)
- Fix bug preventing torrents with 0 leechers from being downloaded [`5e15eeb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e15eeb886355530703ca6d9ab3c2c437a401f52)
#### [v4.0.45](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.44...v4.0.45)
> 26 July 2015
- Clean up some code in kat.py [`029704f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/029704f12c74434c7afaa6386dc38d577ba853f8)
- Disable text factory on DB for tests, read line comments [`fd358f5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fd358f5e4af7d9c2e1247b088029dcce12b613d0)
- Update light.css [`4f8ae57`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4f8ae57ead01efe7f69639ffbd063e5397e8447e)
- Update style.css [`8e37af5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8e37af50befa8e775b066f426d8c39ebe963e57d)
- Changed .col-status to make it fit larger statuses [`f364af0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f364af093ca4a7cfcfbdcbb840bd1d4bcd8c3638)
- What was I looking at? [`ee1e4c8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ee1e4c8db6a3e04837c46e1ed4be09b5e6b33f78)
#### [v4.0.44](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.43...v4.0.44)
> 24 July 2015
- [www.frenchtorrentdb.com] to removeWordsList [`#2186`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2186)
- Reorder other decoding methods also [`a47d396`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a47d396f1857f17e48bda8bea6641028efc3da87)
- Fix restart default page [`3e8c34d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3e8c34dcf171c623158f09a215151f06218564ac)
- Force git reset in user settings. Will fix some issues. [`26b51e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/26b51e102b21afa49bd0c74b44744ab28e7abf00)
- Remove some log lines to avoid spam log [`d6b06ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d6b06ce13da98e509684534386d3626ad5631984)
- Revert "If user has debug enable set DEBUG as min log view" [`fdd4ec6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fdd4ec6b149a9e1a4ab95bea083af237ea2e8e4e)
- If user has debug enable set DEBUG as min log view [`b33ef8f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b33ef8fddcf310869cfab13ae6db2834c1a1068c)
- Update template to show "Loading the default page" and not home page [`abb31e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/abb31e4fd48997723ea08252ff9e3ad695899fc7)
#### [v4.0.43](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.42...v4.0.43)
> 24 July 2015
- [www.Cpasbien.pe] to removeWordsList [`#2181`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2181)
- New word ,to removewordlist [`#2178`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2178)
- Update TODO [`#2177`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2177)
- Add "Collapse" button on subtitles management [`#2176`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2176)
- Crop support image [`#2174`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2174)
- Adds default page option [`#2173`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2173)
- Add Xthor provider [`#2172`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2172)
- Fix log lines and add log lines for URL when code is 200 [`#2170`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2170)
- Add GITUSER to IRC [`#2168`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2168)
- Added some missing network logos. [`#2166`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2166)
- Handle xem_refresh better [`12b3da5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/12b3da5c4926f3fe12d46b15a17c8b964aca407b)
- Multi-Ep results were not checked for qualities, ignored/required words, bad releases, anime white/blacklist, and were using getURL instead of headURL [`17eb849`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/17eb849cddbb13bb3e74540174a508eb848c68c0)
- Bad log formatting [`719b270`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/719b27082c2ae9ece0ecf048656c51da17a6e27d)
- Remove useless vars [`1d008f7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1d008f7480196fc176cc168c01d3bdd4478dc33f)
- Missed import [`335c911`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/335c91134ee92a0f3a4b4cfcc365665781f34fbd)
- new word [`67eb54a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/67eb54a8a2ac314a18fff945c9f5d14450533d5f)
- Fix newznab global name 'params' is not defined [`ec69423`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ec6942375bf6c401d35539b1a0db654c44abe18d)
- Change IRC username prefix to know its an user from UI [`3dc1fa9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3dc1fa9fee1a00147b7effd9e1b8e3cb8f3cf41c)
- Don't remove generic.py [`2de60e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2de60e26b20094fe4199212269d0ba4b2618b5dd)
#### [v4.0.42](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.41...v4.0.42)
> 21 July 2015
- Remove old clients files [`#2165`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2165)
- Adds IRC to SickRage [`#2161`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2161)
- Added missing fyi & soho network logos. [`#2164`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2164)
- Added missing Arena network logo. [`#2163`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2163)
- Missing Recommended Shows [`#2162`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2162)
- Fix default argument when not provided. [`#2160`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2160)
- Fix TRAKT log message to use pattern SXXEXX [`#2154`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2154)
- Show only basename of filename in display show [`#2152`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2152)
- Add an API command to get the fan art of a show [`#2150`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2150)
- Migrate travis to a container-based infrastructure [`#2151`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2151)
- Added missing subtitle flag for Afrikaans. [`#2153`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2153)
- New fixes for log pattern SxxExx [`#2149`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2149)
- Make SxxExx pattern as default in log messages [`#2148`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2148)
- test [`a8041fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a8041fe7b47f1466025ad70e2e99cede8fc31df5)
- Disable auto set as "air-by-date" as it's not a proper code. Let user set it [`dd99b5b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dd99b5bcd96d6fa1888decf7fa63cad01fe2c94f)
- Fix notification when searchin subtitles through web api [`bb196f3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bb196f36019baa9b923e9cc5ed170b84c94db762)
- Fix max title length for issues [`4fac9d2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4fac9d21f35698446c49400ac89d261d64d8c763)
- New log improvements [`2dbd47c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2dbd47c8c01f1a5c00780ea0bd9ac1efc8553495)
- Make "Filter Row" in shows page enabled by default [`999ad6e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/999ad6e833c26f7912da8b44906698796dcc0d12)
#### [v4.0.41](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.40...v4.0.41)
> 19 July 2015
- Add Default Ep Status to WebAPI CMD_ShowAddNew [`#2142`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2142)
- Remove zoink.ch [`#2145`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2145)
- More network logos [`#2144`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2144)
- Added missing bravo (us) network logo. [`#2140`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2140)
- Several network logos [`#2141`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2141)
- Don't allow chained call with command show.getnetworklogo [`#2143`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2143)
- Fix Cpasbien provider [`#2136`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2136)
- Fix error: Filesize would require ZIP64 extensions [`#2138`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2138)
- Add missing api commands to apibuilder [`#2127`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2127)
- Fix search indexers api [`#2128`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2128)
- Ñew word to removedWordList [`#2132`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2132)
- Update helpers.py [`efebf85`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/efebf855f5109e71ff08e25f93cda970063dccd2)
- chiba tv,sun-tv & teletama [`3c82b7a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c82b7a1267bb51cd7b14e8db9faa980360e49af)
- we_tv logo [`b111a79`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b111a797ac83eb2b9841126193a6a1335500fccc)
- several logos [`dabfdce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dabfdce27c1ce703ac8c3d5653ac1e21c15ecba7)
#### [v4.0.40](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.39...v4.0.40)
> 18 July 2015
- Don not consider episodes with airdate = 1 as aired [`#2133`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2133)
- Add TitansOfTV provider [`#2129`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2129)
- Updated CHANGES.md `till 4.0.39 [`#2130`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2130)
- Added missing global & abc (ja) network logos. [`#2126`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2126)
#### [v4.0.39](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.38...v4.0.39)
> 17 July 2015
- Set episodes with airdate as 'never' to UNAIRED status [`#2122`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2122)
- Rename clients py files to avoid conflicts with libs [`53ce36a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/53ce36a9dc336907f81d63e2d0d455c27d11b299)
- Update tv.py [`92e299e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/92e299e31cec13c31504d8dfc74b066389e8a37f)
- Update search.py [`e38274d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e38274d6f33bc2e15092367a8e2aa6bee5e4da5f)
- Update search.py [`95ac7be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/95ac7be53e318d79033c886deb26b04a5a05903f)
#### [v4.0.38](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.37...v4.0.38)
> 17 July 2015
- Added Fox Crime network logo. [`#2121`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2121)
- from lib.module and from module return different objects [`762a0e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/762a0e4d8c14b0a2947adbfa72c91f4151966a5f)
- Revert local scene exceptions to use gh repo [`4eb123a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4eb123ac1973be1b573f78b4491682bfbf90fa2e)
- Revert network timezones to use repo again [`2d1aaba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2d1aabadcffe4e9362b088bfb58ea0d144bd3960)
- Update readme.md a little [`3132c75`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3132c75b6599e90dba0b11d742de06e3c57e43a9)
- Update news.md [`fc3b1c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fc3b1c79c7ac7a73c6ff7e7d9cf1410665a06620)
- Update news.md [`358f683`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/358f683d40dd15518ae782fe50784dc376a896d0)
- Fix bug with scene exceptions, and build [`0657d64`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0657d64e2d0d3feb159d0a41e9b3a407cf520618)
- Fix bug with scene exceptions, and build [`7a542ec`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7a542ece2e6c758868804126c6eb9fdeb3f8a25d)
- Better log message when error downloading subs [`9ebb446`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9ebb446756950aae64d09e2a4d934a5b93571322)
- Fix bullets in markdown [`c25e0d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c25e0d7f30d0f072d08c249552e36b3772b1322a)
- Fix URL with double http:// [`d6aedae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d6aedaef6148d90a14e20710c23e20a27333c948)
- Change show names cache to DEBUG [`47e4021`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/47e40213ec48c53ab160af44c4685ca9f229b890)
#### [v4.0.37](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.36...v4.0.37)
> 17 July 2015
- We need to figure out a better way to handle this [`ef12cae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ef12cae3dd6aa790bd5574ba246d223507b0305a)
- Rename news.tmpl to markdown.tmpl so it can be reusable [`280ddfb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/280ddfb8e3cdf1a5832bdb7480f7f76b7ad474c8)
#### [v4.0.36](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.35...v4.0.36)
> 16 July 2015
- Fix detection of already downloaded subtitles when using a custom subtitle dir [`ef3278d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ef3278d777a45b164795a7a8853e63ec3d0a6df2)
#### [v4.0.35](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.34...v4.0.35)
> 16 July 2015
- Updated subtitle flags. [`#2112`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2112)
- Small Typo [`#2115`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2115)
- Add Cpasbien provider, update Libertalia [`#2114`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2114)
- Update Libertalia not to use urllib2 anymore [`c5d579a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c5d579af7d3476fd267b84c4639cbb51d450b34f)
- Update news.md [`19dae7d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/19dae7d8e995af4664edecb0be578fee7b6bf5e2)
- Fix flags on history page and info lang [`0ebb1bd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0ebb1bd8ca7c88d3c517e0eb0a7d7c9ea3b11e77)
- Update news.md [`9de06c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9de06c41ce60153175ee79c08a0cc5bc62a3c6b0)
- Update news URL [`a62f64d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a62f64d7a1c0dee3542b42f68a12905a506bf3d3)
- Update news.md [`2312f65`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2312f6567d5338077d6ab0396da1e8e44cd6085c)
#### [v4.0.34](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.33...v4.0.34)
> 16 July 2015
- Add FrenchTorrentDB and Libertalia providers [`#2106`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2106)
- Use markdown2 to parse github markdown pages [`ba1babf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ba1babf427ec021637af1cb5b917dbf73f58152a)
- Move and improve subtitles codes check [`4d9663c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d9663c13fa520287aa351fad1a508a14fbd1f26)
- Move and improve subtitles codes check [`9c373c2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9c373c2d5fae6656fd44eb98b74aa46036520e17)
- Bug in PP where scene numbers always used [`776516f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/776516f8cf050e471746a0d2d10821251ba91083)
- Create news.md [`281fb27`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/281fb27691be4416451e174f83c1d56f481c2ad1)
- Update webserve.py [`ec4e3ec`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ec4e3ec0e8793bfa84613773396568c60d81c5e8)
- Create news.tmpl [`3ad822a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3ad822a094e5146d0006dcd1dd026e428e0db06c)
- Fix flags on history page and info lang [`1e2bcad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1e2bcad2f1d668deb6257ae698b45a8bad0e3769)
- Performance improvement in subtitles code check [`8e38759`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8e38759d53db01998426e0add03e089be5076007)
- Performance improvement in subtitles code check [`f3b5727`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f3b57275d6b43c019a4513e4461f6a7a96d7ffde)
- Update inc_top.tmpl [`5dd7732`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5dd77326422d30546fac32d9c8a47a83ea6ac87b)
- Changes spaces [`6305bbd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6305bbd4c3ce103c8135fc81ce3e7a5c0c0d8932)
- fix-donate [`921c111`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/921c111d05700e27a1a626184ac25d27c9e68b09)
#### [v4.0.33](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.32...v4.0.33)
> 15 July 2015
- Added missing subtitle flags. [`#2107`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2107)
- Fix trakt return [`#2105`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2105)
- Fix trakt exceptions when connection timed out [`#2104`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2104)
- Fix old subtitles codes in DB [`01138de`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/01138de791001a4ae096dd6dcb996629150edac0)
- Fix html tags [`df8b042`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/df8b0428a12845aded67ecf96071ad40006419f4)
- Updated subtitle flags. #2 [`88c3fa8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/88c3fa8e40a8cf33178ed473d320d4daf2a6c950)
- Updated subtitle flags. [`0b91408`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0b91408daec1131222631fa14099668e0268d2b8)
#### [v4.0.32](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.31...v4.0.32)
> 14 July 2015
- Re-add namecache creation to SickBeard.py [`#2102`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2102)
- Fix for SiCKRAGETV/sickrage-issues#2079 [`#2095`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2095)
- Add an API method to get a network logo [`#2090`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2090)
- Updated the provider icons. [`#2092`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2092)
- More sufixes and prefixes [`#2093`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2093)
- Better integration in Chrome for Android [`#2089`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2089)
- Small visual improvement in server status [`#2091`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2091)
- Fix for SiCKRAGETV/sickrage-issues#1927 [`#2088`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2088)
- Update chardet hoping to improve guesses [`4c87b84`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4c87b84664f8ae7198b980f322079e56d7984fe7)
- enum34 dependancy for chardet [`b06dfaa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b06dfaaf8a2817fb77b419c3ca5630cf1f298b93)
- Missing guessit test files [`13347b4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/13347b4a071bee5c4e90e5845ba02487bd8add15)
- Correct a problem where name was reassined as a list in tntvillage, resulting in error on second iteration. [`1e95c08`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1e95c084ed3faa55ac0db8f1bcecf24906b7475e)
- Encode freemobile msg and title with utf-8 [`bbe5aa2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bbe5aa2cf2eeff261503602eea393e3460389dea)
- Fix parser log [`27ab189`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/27ab189b43b9fd38747dd89d0f7f314f4f22e194)
- Fix log message showing 'no released episodes' when It shouldn't [`7146315`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7146315fef7d097aa8ee78753cd90ff003b8f688)
- Fix cache log message [`fe8a85f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fe8a85fa92682d188f7fa7028a42828d6341afce)
- Only notify plex if there's title and update_text [`4a69012`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4a69012f67f7e3bca8babaee0c4638b390429a9f)
- libs are already at the start of sys.path, importing from lib or lib. causes import issues within previously imported objects [`ad31d9e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ad31d9ee9812d1215cc7032601cbbeead8cc923d)
- Paused shows: unaired episodes should honor default ep status [`ff58945`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ff5894546bae22ae6f5bb8b4a767472628fb0062)
- Make botton "backlog search" as timeleft [`c2e5344`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c2e5344469b9a02174f5447df04ae74213bf6944)
- Move subtitles flags to their own directory [`76e4670`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/76e46708b538065df56e6d7e1d46e8087f7082b8)
#### [v4.0.31](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.30...v4.0.31)
> 12 July 2015
- Update removed words [`#2083`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2083)
- Update changes.md util 4.0.30 [`#2082`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2082)
- Remove the hard linking for subtitles search - too many problems. Fix ui notification for subtitle downloads [`6b98cc6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6b98cc65a679ca7e3670b545fc884c793fafc882)
- fix scene exception update using mass memory and missing a bunch of exceptions, stop hdd thrashing [`5ee5c00`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ee5c003ed42adcc67f011967a3aaca58ba6fd1a)
- use .iteritems() instead of .items() - everywhere, to save processing and memory. [`9880d06`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9880d06f76c7078e40e19b16fd0cc64e7f6f6434)
- Fix provider sorting, enabled are always at the top now. [`e06f9fa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e06f9faf95c24bcb852ef9bc35dc17f7d124dd6d)
- Better path control for scene_exceptions [`1babae4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1babae4509b000ba50bac13074da078f1aa8c58e)
- Only warn if kodi is unreachable [`1832ecc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1832ecc4bfec200d1600264e5a8f48408c1dc745)
- Loopy import??? [`c2436b4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c2436b4f76029bfe903ba4a4bb0792a1d2f6c6aa)
- Fix status string in dailysearcher [`232069a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/232069a0a027e1f2bef562e1515beaccc7540b61)
- Change donation page url to wiki page [`1b3ec33`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1b3ec33cc3be32606f090a93d33f4cdb39547257)
- hotfix - Need https not ssh for github (accepting github key issues) [`5e47d9f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e47d9f4b34567c241e19c1a8edb37e5248c8036)
- Update remove words [`f487290`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f487290c0f5db75314b4f1466c6b31036acf138a)
- Fix some incorrect permissions [`cbe9f1e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cbe9f1ea99f233f89071bda87a552a9074b8aed4)
#### [v4.0.30](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.29...v4.0.30)
> 9 July 2015
- Fix for SiCKRAGETV/sickrage-issues#1927 [`#2074`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2074)
- Add main TV category to newznab categories [`#2075`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2075)
- Fix log messages with chars like \xc3\xa7o [`#2073`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2073)
- Remove Show from SickRage if ended and full watched [`#2011`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2011)
- Add API methods to check for update and perform update [`#1958`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1958)
- FNT & BLUETIGERS PROVIDERS [`#2063`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2063)
- itorrents.org caching website [`#2059`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2059)
- FNT & BLUETIGERS PROVIDERS [`#2057`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2057)
- Remove www from HDT [`#2052`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2052)
- Comedy Central Updated Icons [`#1909`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1909)
- Updated provider icons. [`#2048`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2048)
- Change message about unable to find show [`#2049`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2049)
- Updated subtitle provider icons. [`#2043`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2043)
- Add log message when ignoring result from provider [`#2044`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2044)
- Add exception handling to sql commands [`#2042`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2042)
- Add new exception handle to avoid break loop th files [`#2041`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2041)
- Add more debug log message to showrefresh [`#2039`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2039)
- Subtitles download now, only error checking and Language code convers… [`#2040`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2040)
- Temporary remove torcache due to JS timer [`#2038`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2038)
- Glob still wrong -.- [`#2037`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2037)
- Icon for podnapisi.net was missing in the new Subliminal. [`#2035`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2035)
- Cosmetic change and disabled add paused if trakt rolling enabled [`#2036`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2036)
- Add guessit dependancy stevedore [`#2034`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2034)
- Subliminal continue [`#2033`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2033)
- Fix italian language recognition for tntvillage provider [`#1963`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1963)
- Add timeout to Boxcar2 [`#2024`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2024)
- Added 4.0.29 to the changes [`#2027`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2027)
- Fix SiCKRAGETV/sickrage-issues#1930 [`#2026`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2026)
- Missed requests import zzz [`#2025`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2025)
- Metadata needs a session too! [`#2023`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2023)
- Wrong import [`#2022`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2022)
- Fixes to subtitles, none enabled for now but close! [`#2021`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2021)
- Fix a logline string formatting error in SCC. [`#2020`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2020)
- Honor usenet retention setting. Fixes SiCKRAGETV/sickrage-issues#1910 [`#2019`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2019)
- Fix for PP issue and [ or ] in folder names. Fixes SiCKRAGETV/sickrag… [`#2018`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2018)
- Update subliminal [`#2017`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2017)
- Add babelfish dependancy for new guessit, update guessit [`#2015`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2015)
- Update cachecontrol, don't clear it's cache, dont build nameCache or … [`#2016`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2016)
- Updated search stings with airdate [`#2014`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2014)
- Added/redone some provider icons. [`#2013`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2013)
- Pass headers through also, better exception log [`#2012`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2012)
- Check if user needs to add token to PLEX [`#1969`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1969)
- Change Trakt genre url [`#2010`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2010)
- Updated Changelog [`#2007`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2007)
- Forgot indexer scene_loc change [`#2009`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2009)
- Update enzyme to work with subliminal [`112ac3c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/112ac3c7e8d74fc4650a892f9b87f65f8622d1bc)
- Proxy and session fixes: [`ddffe65`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ddffe6516fe448c27f5b357f784e4a54ff9f1daf)
- More subtitles changes [`fae8a12`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fae8a12d21fe159cef3df372c89f289175a80e83)
- Updated changelog with changes from 4.0.20 `till .28 [`1193418`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/11934183cf095c950625122c3ab0c3fccff74fde)
- Various fixes to subtitles. [`360392c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/360392cb145d9a5a21a93f34b681972590ddf654)
- Use a temp hard link to get better subs matches [`a0b43d0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a0b43d09545822b9780cdbc98dd36af191b69dde)
- Various fixes for subtitles [`6361b6e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6361b6ee3b8765f224518021eba060b708a53fd5)
- Don't raise exception when no token set or server unavailable [`15a76f2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15a76f27ced027e21fb62fdac77e6ba3c1fa4388)
- Cosmetic change and disabled add paused [`8cf5410`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8cf541027ec6ba278e4d5f6dc632bf7b7475467b)
- Fix build with new cachecontrol, must have a session now - cc wont create it! [`35ebfba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/35ebfbab66d103d6038f32a282aea34d9aab2a45)
- More work on subtitles [`ae336d8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ae336d8579f1029154b5ae985ded405ef1255988)
- Fix manage of unaired episode according to trakt rolling download if enabled [`5d39b05`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5d39b05d0b4062ce1eea52b336228411ce827b42)
- fnt.png => 16x16 & seeder and leechers support [`56f5b6d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/56f5b6d271246084c9b7f7f23a56cf01122b9dec)
- Cannot add lib in import calls for subliminal [`08bf6b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08bf6b3078ce86e10621568fabd8c10ab6cd9233)
- Monkey patch new subliminal to run on py2.6 [`fdb7ca1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fdb7ca1936c1c3c21b5e3025ade691c2c3e1f742)
- Disable second guesses, but wrap in try/except incase we need them [`7d3a239`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7d3a2396663be51f4173e10b1376b9c25e4b62ab)
- Use configured remote when setting repo url [`7fd5a63`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7fd5a63f2bcaaaea477fbcc3cd20e3865bad8d29)
- Make sure to remove hardlink and return if scan_video fails [`2586ec9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2586ec9f299de389c7849f321a2638e1ab75f6bc)
- Reorder if/else to make readable [`897cd9c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/897cd9cf8dc682186187d9b0b41237f319ff7b03)
- Change some errors to warnings in updater, when commit is newer than master or network unavailable [`029dd7b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/029dd7bff9d4fc99b0ed6587a1a24f51dfab36e0)
- Commit after massaction/action to reduce memory consumption 2-3k queries in memory?? and remove Locking. isolation level is non/deferred by default [`3ab23bf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3ab23bfc94d54244e24b00c34b7b6cad981f6d32)
- NullHandler [`fe5d4a4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fe5d4a484de2c8d38c7425987bca2d59b63ebff0)
- Use travis on all non-master branches [`c386f24`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c386f24ebe3fbb1f7afc83fe74bcc463d4ff4c25)
- Monkey patch guessit to work on 2.6 again, might be more patches needed if issues pop up [`06b0303`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/06b0303b6300e93ba158a6b47f85d30af0a27c4a)
- Don't fail ssl test if response is ok! [`edab960`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/edab96071fcc92703318e287bdde8e34d30a24c7)
- Need to use real path, or subs also get saved in wrong path [`79067ff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/79067ff5249c57a54808af0204513ee573e7e82b)
- Missed a session for cachecontrol [`2a333c3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2a333c3fc95ee8ab199dd9dddfa1bdc4c0ddfdd0)
- Missed this change [`3367568`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/336756806eec933f3a56bd2c2d7daea77d6a6ee8)
- Fix release_name extension detection for subtitle downloads [`3f294bc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3f294bc7c9f6f4b8f599ef7ec883fe963baf8368)
- Wrong module for method - subliminal.subtitle.get_subtitle_path [`42e3cea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/42e3cea1e537a8c051e649d4e7f8d3b8df708eea)
- Forgot myself [`4311ff4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4311ff464d71d7b65bedcc86e01a6179b10563ac)
- Missed import [`aa9c1bf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aa9c1bf1ca2bf3df9cd33fe4e798c8247dfe1881)
- Revert "Comedy Central Updated Icons" [`c459c33`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c459c339475bdeded14d3f4fd333d93ee52a740d)
#### [v4.0.29](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.28...v4.0.29)
> 25 June 2015
- Fix scene exceptions and network timezones paths to be absolute [`#2008`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2008)
- Fix resultType not in class Proper, use head instead of get request w… [`#2005`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2005)
- Fix and clean SCC, don't spam them with faulty queries, and process e… [`#2004`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2004)
- Remove submodules and use subtree instead, submodule isnt prepopulated [`#2003`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2003)
- Why use requests if we arent going to verify anyways? Maybe requests … [`#1992`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1992)
- Try again with the name_cache lock. there was a deadlock. Add submodules for scene_exceptions and network_timezones [`#2002`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2002)
- Move name_cache lock to fix error of list modified during iteration [`#2001`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2001)
- Missed import! [`#1998`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1998)
- Change so travis can cache pip installs between builds [`#1999`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1999)
- Remove https from rarbg token [`#1997`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1997)
- Sleep in SCC, move torrent content download to after all checks to make sure we want it. [`#1996`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1996)
- Try #2 on Failed to load url error [`#1995`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1995)
- Failed to load URL? This section needs debugged hard [`#1994`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1994)
- Add NZB.Cat to providers, per KingCat request [`#1993`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1993)
- Merge commit 'dc627a9ac4886be728aaaa7403b78924f30850ce' as 'lib/scene_exceptions/tvdb' [`4f63ea3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4f63ea3b512e3126ffbfc939552d4ffd5185a825)
- Bad encoding [`94d9e7f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/94d9e7fc46dda37544db2cae0ee8dbd75f15b644)
- Merge commit '35e6e584b5b316f57a9b4f6a874b8807fa36931d' as 'lib/network_timezones' [`30142f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/30142f6b89f76529714ebcc935b11acf0e4352a3)
- Merge commit '08555d15cb2bab1c66aa5e8048db8c580c3a1c4b' as 'lib/scene_exceptions/tvrage' [`56d40f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/56d40f973d4f21748b0b2516d7bf720f7becb8db)
- Why use requests if we arent going to verify anyways? Maybe requests is broken with verify off [`f8d4e26`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f8d4e264ae27d3eecab5f61e3ebf9b006d98b26b)
- Network timezones loaded from git submodule [`059e4cc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/059e4cc8a809090fba695cd60e9822fdcfedc612)
- Use exceptions from submodules, so we don't need to grab from github [`349e72b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/349e72b5dd855bee852e8fc64ac7c0527b9a1146)
- Remove submodules [`c00c6fc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c00c6fc58807f9a93537cf7d03f3ab38a8d15aff)
#### [v4.0.28](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.27...v4.0.28)
> 23 June 2015
- Change USER_AGENT back to SR now that problems are fixed. Hopefully w… [`#1991`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1991)
- More fixes 2 [`#1990`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1990)
- If these are too high, they are being used in places they don't belon… [`#1989`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1989)
- Test for write/permissions problems and warn [`#1988`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1988)
- Update tornado to 4.1.0 from 4.1.0dev1 [`#1987`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1987)
- Set maxage to today-airdate to limit results to relevant results, and… [`#1986`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1986)
- Missing import for show_name_helpers, Fixes SiCKRAGETV/sickrage-issue… [`#1985`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1985)
- Missed import [`#1984`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1984)
- More fixes [`#1983`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1983)
- Oops [`#1982`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1982)
- Multiple fixes [`#1981`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1981)
- Fix torrentday [`#1978`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1978)
- Remove html tags from ui.notifications [`#1973`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1973)
- Add Trakt empty token error message [`#1972`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1972)
- Change propers code for newznab, hopefully fixes it [`998d26c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/998d26c9b25ce4fca55dfd634d0ec27937d57dab)
- More newznab limitting/fixes [`01770bd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/01770bdf6eab3284a6e90b89495782377e4fe979)
- Name cache cleanup [`dc9bad3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dc9bad3a976e2099c3f60cfa33396ed342b2f8a9)
- Fix group sometimes not showing in compact history [`a7ca5a8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a7ca5a8d10ff8c8f0bfd5db96ad6cf65a38a0fdd)
- Catch exceptions from providers in daily searches [`b6f913e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b6f913eb8984ebb2127a5e84604fa5bc4671bbd4)
- Use womble for feedparser test [`e953a87`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e953a8740c538aa06533d1f33cc37a3e737f120c)
- Fix results from cache not honoring ignored/required words [`ddeaf99`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ddeaf996786635ca05af497e68b5591a2474b0b0)
- Filter .torrent and .nzb from pp list of files [`e9fd2e5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e9fd2e564cf078229380013deab3f1f98be5053b)
- If these are too high, they are being used in places they don't belong! Don't change them [`09e5ec3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/09e5ec3f1ddf481462ae6b4f1d6226d5ac7d0c5f)
- make sure we are cleaning up destination filenames before renaming [`3dbb738`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3dbb738d8b56b9946ae056ef576a58c9e3f52c83)
- Update webserve.py [`b84ad2c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b84ad2ca826af5c2897baeed97bbe5983affa55d)
- Disable feedparser test again. [`5a1869b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5a1869b21bcf980b64676294f57c5dd3310ac926)
#### [v4.0.27](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.26...v4.0.27)
> 17 June 2015
- Fixes /SiCKRAGETV/sickrage-issues#1814 Fixes /SiCKRAGETV/sickrage-iss… [`#1971`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1971)
- Fix remove default ep status [`#1970`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1970)
- Remove "Default Episode Status" from editshow [`#1968`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1968)
- Remove Oldpiratebay provider [`#1967`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1967)
- webapi CMD_ShowPause doesn't update database [`#1947`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1947)
- Properly import sickbeard.exceptions.ex [`#1966`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1966)
- Update RARBG to new API (v2) [`#1964`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1964)
- Warn on bad gzip header response, instead of error [`#1965`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1965)
- Oops, searches weren't ran at all [`#1962`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1962)
- Limit newznab searches to 400 results, clean up logging [`#1961`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1961)
- Fix HDT removing first letter of the file [`#1959`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1959)
- Remove eztv and ezrss due to general scene skepticism about the shady… [`#1956`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1956)
- Try to get the best quality from the best/archived list on first snat… [`#1957`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1957)
- Add alt.binaries.teevee [`#1955`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1955)
- Remove eztv and ezrss due to general scene skepticism about the shady nature of their takeover [`be1528e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/be1528e5f19b9a5f846ad2110f32a2f06ce688f4)
- Remove OldPirateBay provider [`e6129a4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e6129a4a423e87a2c1aaffdf37cbb7b8ef66e1b8)
#### [v4.0.26](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.25...v4.0.26)
> 13 June 2015
- WindowsError undefined on linux, but WindowsError and IOError are jus… [`#1953`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1953)
- Allow select SDTV for Best/Archive quality in MassEdit [`#1951`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1951)
- Strip [vtv] and -20-40 From release group. [`#1950`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1950)
- Fix removeWords, ignoreWords, requiredWords..... [`#1949`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1949)
- Allow SD as archive quality in custom qualities, SD is better than Unknown, and some of us want to use smaller files for 'archived', meaning "we wanted an episode as soon as it was available, but we want a specific quality once it is available" . Works if there is only 1 quality is set in archived quality for now. [`#1948`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1948)
#### [v4.0.25](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.24...v4.0.25)
> 11 June 2015
- Add ranked and sorting options to RARBG settings [`#1946`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1946)
- Sort rarbg results by seeders, not by newest. Newest torrents tend to… [`#1945`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1945)
- Unranked rarbg and pp logfix [`#1944`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1944)
- Fix torrage and zoink.ch, because torcache has a timer and returns ht… [`#1943`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1943)
- Show scene exception help info even when no exceptions are set [`#1940`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1940)
- Fix SiCKRAGETV/sickrage-issues#1554 [`#1942`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1942)
- Update RARBG category to 'tv' [`#1939`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1939)
- Fixed verify_freespace check and return False on isFileLocked check [`bdadba3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bdadba3f21aec0193bdfc1e490e00a410e61e0b5)
- Log regex mode only on error, disable unnecessary pp messages [`af7bbac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/af7bbac7f07b0f6a8b9ba9b18359a9971acf46ba)
- Fix torrage and zoink.ch, because torcache has a timer and returns html instead of a torrent [`b9ec121`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9ec121df04ee8048c052af654615cf1696b38a1)
- We want all results from rarbg, not only internal right? [`6b816ad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6b816adfe5ef3a1315cd40791bf67ef9966050df)
- Update thepiratebay url [`43d10cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/43d10cba2fe91166825907a352a3d6091ca8befe)
#### [v4.0.24](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.23...v4.0.24)
> 7 June 2015
- Fix for potential bad episode airdates preventing SR from starting. [`#1936`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1936)
- Nice and clean info now. Need to disable some of the debug logs compl… [`#1935`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1935)
- More log cleanup and fixes. Move lower level actions to debug [`#1934`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1934)
- Logging changes and improvements. [`#1933`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1933)
- Update initial schema for failed.db and cache.db, Big clean up of log… [`#1932`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1932)
- No need for the dropdown, the extra items appear on the right under t… [`#1931`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1931)
- Small change for additional layout. [`#1922`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1922)
- Update initial schema for failed.db and cache.db, Big clean up of logging on startup by moving some INFO->DEBUG. [`c2d334b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c2d334b59e7053524005561d63881d916ee3f9de)
- Mod kodi log messages for updates and notifications, warn on errors, debug on actions. Less log clutter pl0x [`5d8a014`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5d8a0140774a49233d9cdde07b4f9d7f1d752be6)
- Nice and clean info now. Need to disable some of the debug logs completly to clean up debug logs! [`54e5197`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/54e5197749f8139c8d1cb7c8fd0854b59f1e5d17)
- Clean up some more logging, especially when using hard links [`0e986b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0e986b3e33f7bfa77fe5ac7aaac44284ddd4be92)
- No need for the dropdown, the extra items appear on the right under the navbar [`cf3aabb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cf3aabb975a6a41c195b4fb0bcb9a07e25b96c30)
#### [v4.0.23](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.22...v4.0.23)
> 1 June 2015
- Update regexes.py for the web site ISLAND FANSUB (ANIME) [`#1925`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1925)
- Change urls to use http github.io pages from our repos [`#1930`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1930)
- Change image download issue from error to warning [`#1929`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1929)
- Update regexes.py [`626da7d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/626da7d2fd52658bc5e20c304a8d6ad267ab6675)
#### [v4.0.22](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.21...v4.0.22)
> 27 May 2015
- Update both requests to 2.6.0 [`#1928`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1928)
- Change check scene exceptions from error to warning [`#1921`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1921)
- Fix for issue #1691 [`#1927`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1927)
- Fix name of attribute in providers.newsznab.NewznabCache._parseItem() [`#1919`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1919)
- Failed Download Handler: Size Fix [`#1918`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1918)
- Try to fix 'utf8' codec can't decode byte [`#1916`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1916)
- Uppercase 'in' and 'a' in fuzzy dates. [`#1917`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1917)
- Lowercase date fuzzies were ugly, and the 'last' keyword suggests > 7… [`#1914`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1914)
- Add failed option to PP API [`#1887`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1887)
- Also catch BadStatusLine [`#1913`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1913)
- Lowercase date fuzzies were ugly, and the 'last' keyword suggests > 7 days ago. ie: this past sunday (2 days ago) is not the same as last sunday, as last sunday was 9 days ago if today is tuesday. [`b525eea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b525eea3ab63a55b3056714d4ae3dce51db4e883)
- Fix name of attribute that newsznab returns [`016c646`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/016c646bf360b1883e24862797398ad36b503f5c)
- Revert "Update template" [`e1fd869`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e1fd86962e706271ea6438d37cc3cb58b9064f38)
#### [v4.0.21](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.20...v4.0.21)
> 17 May 2015
- EZTV Provider: save all possible links found in the homepage [`#1910`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1910)
- Added missing funimation channel network logo. [`#1902`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1902)
- Network Logos [`#1904`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1904)
- Added and Corrected several Network icons [`#1898`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1898)
- Fix#1603 - Manual add to Black / White list failed [`bea2461`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bea2461912d49bc0f352f8dee165f988d9ffacea)
- Updated Discovery Channel logos to current one [`8a78d72`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8a78d729c0e4b741508120290ec63ce750dad6ba)
#### [v4.0.20](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.19...v4.0.20)
> 10 May 2015
- torrage.com domain expired, zoink.ch nginx misconfigured or service s… [`#1896`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1896)
- Fixes due to html changes in http://eztv.ch [`#1884`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1884)
- Fix funky Quality Names. Fixes SiCKRAGETV/sickrage-issues#1508 [`#1885`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1885)
- Added missing "The Anime Network" logo. [`#1890`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1890)
- re-enable feedparser test, as lolo.sickbeard.com is operational again. [`#1891`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1891)
- Change sr_tvrage_scene_exceptions to use SiCKRAGETV repo instead of e… [`#1892`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1892)
- Add flexibility when determine title from link in eztvapi.re: [`#1858`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1858)
- SCC doesn't support searching dates with pipe characters. Use '.' [`#1873`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1873)
- Fix webapi error when show search returns 0 results. [`#1870`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1870)
- Replace SSL Error with a url with information. Disable issue submission of the infamous SSL errors. [`#1880`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1880)
- Move init/upstart scripts to their own folder to organize and clean up the source. [`#1879`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1879)
- torrage.com domain expired, zoink.ch nginx misconfigured or service stopped. [`544664f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/544664faa06f3c221d25dd33e931eaae881b5424)
- Update Regex to be more specific to for replacement [`1f94101`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f94101d0acaae6702f28634533d5087eb69c6f5)
- Didn't rewrite the message in the log. Oops. [`7558355`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/75583553ced342e90c2b985f2b81d9fe8dc533e8)
#### [v4.0.19](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.18...v4.0.19)
> 4 May 2015
- Add pyopenssl libs, and a inittest [`#1872`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1872)
- Center Search icon on displayShowTable [`#1874`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1874)
- Upstart expects you to start things in the foreground. Simplify script, ... [`#1875`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1875)
- Added some missing Network logos. [`#1869`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1869)
- Revert "Update requests library from v2.5.1 to v2.6.2 ff71b25e" [`#1867`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1867)
- Update certifi certificates [`#1862`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1862)
- Make sure we are using our included libs, and not system libs, by provid... [`#1864`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1864)
- Remove unused libs, Thanks SickGear [`#1865`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1865)
- Fix build status, feedparser uses lol.sickbeard.com and they no longer e... [`#1866`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1866)
- Fix travis reporting failed builds as successful [`#1861`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1861)
- Update requests library from v2.5.1 to v2.6.2 ff71b25e [`#1860`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1860)
- Remove reference to readme-FailedDownloads.md, which doesnt exist. [`#1854`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1854)
- if re.search returns None due to no match, .group() will cause an exception [`#1856`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1856)
- Update requests library from v2.5.1 to v2.6.2 ff71b25e, possibly fixing some ssl errors [`b08b1c5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b08b1c58f3341f34fc36ae5f673552305f3297e0)
- Make sure we are using our included libs, and not system libs, by providing the full path [`c16b2c1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c16b2c1c769a2c7c8d93707ff44ac00894501c6f)
- Fix build status, feedparser uses lol.sickbeard.com and they no longer even have a feedparser test, and have changed the api. [`4aac134`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4aac134c741e6c84324f06d258d26a0d953f2a8b)
#### [v4.0.18](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.17...v4.0.18)
> 26 April 2015
- Update changes [`#1853`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1853)
- Update template [`#1852`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1852)
- Make check_setting_int understand True/False from settings [`#1850`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1850)
- Fix upstart multi pid [`#1846`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1846)
- Missing chmod [`#1847`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1847)
- HOTFIX: convert the bool to int for default web_use_gzip config [`#1848`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1848)
- add multi-search IPT [`#1765`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1765)
- Enable trending shows only if Trakt is enabled [`#1836`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1836)
- Use 'WARNING' logger for 'No NZB/Torrent providers found or enabled in the ... [`#1835`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1835)
- Block issue submitter from running more than once at a time. Fixes #1305 [`#1833`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1833)
- Fix BTN [`#1832`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1832)
- BTN - Show warning instead of error for api call exceeded [`#1818`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1818)
- Build tests [`#1812`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1812)
- Cat sickrage.log generated by unit testing if travis build fails. [`#1813`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1813)
- New KAT domain page [`#1822`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1822)
- Fixup regex for issue submitter, Dont allow dupe app submitted issues. More [`#1820`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1820)
- Match "bluray, blueray, blu-ray, and blue-ray" for determining qualities [`#1831`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1831)
- Fixes #1401 - SD Blueray not matching [`#1830`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1830)
- Updated the network logos. [`#1829`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1829)
- Fix Morethantv (http to https) [`#1823`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1823)
- Fix scenetime index bug (sickrage-issues/#1354) [`#1828`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1828)
- Fix missin amActive [`#1817`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1817)
- Fix missing import traceback [`#1816`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1816)
- Unit test: change journal mode when in unit test [`#1807`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1807)
- Build tests fix, replaces #1525 [`#1750`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1750)
- Remove indexer from tvshow.nfo and series.xml [`#1804`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1804)
- T411: Catch invalid data, log, and continue [`#1802`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1802)
- Merge pull request #1833 from miigotu/block_submitter_spam [`#1305`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/1305)
- Block issue submitter from running more than once at a time. Fixes #1305 [`#1305`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/1305)
- Merge pull request #1830 from miigotu/fix_#1401_sd_blurary [`#1401`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/1401)
- HotFix for: local variable 'subtitles' referenced before assignment [`#1359`](https://github.com/SiCKRAGETV/sickrage-issues/issues/1359)
- Fix import path on individual tests so they can be ran independantly, from any directory. [`96b2df4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/96b2df465c7f7f6a98891f88cdf138329cfce8d5)
- FR#1040 - Collapse passed seasons [`1196c8c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1196c8c2d19c2ab2a3dc4edff07027a82da20ffe)
- Fixup regex for issue submitter. [`2791e33`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2791e33ab0e99b7b0fbd954f859661d162d54ff7)
- Fixed scenetime index bug (sickrage-issues/#1354) [`6d5a998`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6d5a99872122a8ff65762a914adef325dea197d4)
- Replace error title submitted to issues with the error message if title is missing [`3dd3a70`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3dd3a70eda3d9d9a0a3d089ffddcfc07c0fc559a)
- Blacklist issue_submitter test to avoid fake exception issue spamming, this should be tested manually from time to time. [`228b234`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/228b2347b282f0f515d20d5973cf498b9923fbe9)
- Fix epsearch only searching first wanted episode when multi-ep search [`09e8ca0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/09e8ca0988695b27b4da5d97fb49f983021f8f25)
- Fix Plex notification status check [`645fa66`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/645fa669d1552ac27be1cd3aa160876a024881e7)
- upstart script was broken, spawned 2 instances, killed only 1 [`66edcdc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/66edcdc4b649fcde47d07bc4308872746b88c2ed)
- Updated and New logo's [`3ec1358`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3ec1358d536114a6ac85d902c4ed1403c5d6172e)
- Merge pull request #1806 from abeloin/hotfix-serviceerror [`0111bc8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0111bc8e4e894ac8616011ed71ba34dfaedb0cd9)
- Merge pull request #1806 from abeloin/hotfix-serviceerror [`975c0dd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/975c0dd208c59cac8fd8a77a91da5d1dfc7235df)
- add multi-search [`d20d7c8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d20d7c8b44f1313c0680cc5bcfc095210bf8de22)
#### [v4.0.17](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.16...v4.0.17)
> 19 April 2015
- Update changes.md for 4.0.17 [`#1800`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1800)
- Update IPTorrents search URL 2 [`#1799`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1799)
- Update IPTorrents search URL [`#1798`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1798)
- Show subtitle service unavailable as info [`#1796`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1796)
- Fix code description error [`#1795`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1795)
- Fix url error code description [`#1793`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1793)
- Added qbittorrent support [`#1769`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1769)
- Check if url error code is mapped [`#1788`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1788)
- Manage Rolling Download on unpause from submenu button [`#1789`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1789)
- Fix NameError: global name 'ShowObj' is not defined [`#1790`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1790)
- Auto determine indexer when indexer tag not present in nfo [`#1757`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1757)
- SceneTime.com torrent provider [`#1763`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1763)
- ShowUpdater: referenced before assignment curQueueItem [`#1753`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1753)
- Added msg for partial download of multi-episode torrent isn't supported [`#1777`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1777)
- HTML changes of https://eztv.ch [`#1771`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1771)
- proper: saveSearch broken for download propers [`#1778`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1778)
- iptorrent: Add missing import [`#1758`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1758)
- Catch all errors from Kodi notify [`#1767`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1767)
- Ignore OSError when obtaining the size of a path. [`#1762`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1762)
- Add user agent to RARBG [`#1768`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1768)
- Catch emailnotify smtp error. [`#1759`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1759)
- rarbg: remove urllib.quote [`#1770`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1770)
- use gir-notify instead of pynotify [`#1705`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1705)
- Add RSS to EZTV provider [`#1689`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1689)
- Fix for xml_declaration unexpected keyword in python 2.6. [`#1745`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1745)
- Change timeout errors to WARNING in clients [`#1760`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1760)
- Plex Notification fix [`7f89b58`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f89b5828a39e63b1d03417585fb1aa982dde9c4)
- PNotify Update [`c53a3ad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c53a3ad015848c62eb5effe076273a2edebba668)
- FR#835 Patch 1: Move pause to submenu [`d0a0ee3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d0a0ee3204d425caa83ff33edbc621341f748e50)
- notifiers/libnotify: use gir-notify not pynotify [`bb5020c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bb5020c6e6c84327cdd5f49a6cad8f0a923a027f)
- Update Plex.py [`dc71f72`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dc71f72c038cb670a7d87f4cd5988edfd22ab18e)
- Followed @abeloin suggestion [`2930460`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2930460d5d212d7a5163e885be61c22fc034752d)
- Use better logging for get_size exceptions [`8db53be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8db53becbaa8bac2708ae9fb9939d942b071d385)
- Fix issue 1193 [`4d549f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d549f6d657b6020562adbae3faea019ea05b52a)
- Revert "Change Opensubtitles 503 error to warning" [`28907c6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/28907c6009420a271768600737408e20140bbd9d)
- Change Opensubtitles 503 error to warning [`9c184d9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9c184d95fb52ad2deaacfbbed71fcce04340818b)
- Fix unknown quality being accepted as a valid quality in PP [`c8da24e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c8da24eb7e18329af13eeee8a8d5e475154de5d0)
#### [v4.0.16](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.15...v4.0.16)
> 13 April 2015
- NYAA: Switch from cat 1_37 to 1_0 (All Anime) [`#1755`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1755)
- Update changes.md [`#1751`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1751)
- Tornado: Ability to switch gzip on/off via config.ini:web_use_gzip [`#1740`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1740)
- OldTPB: Check if the returned results are proper|repack [`#1735`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1735)
- EZTV: Temporary fix for getURL json [`#1739`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1739)
- Check getURL response before return [`#1727`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1727)
- Scheduler: Various fixes [`#1734`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1734)
- home filter: change to allow to use parsed data for active(yes/no) [`#1732`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1732)
- Show currently running task in show queue [`#1730`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1730)
- Update changes [`#1717`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1717)
- Add TRAKTROLLING to filter in viewlog [`#1719`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1719)
- RarBG: Retry 3 times before failling. [`#1728`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1728)
- Missing file changes from rebase on the scheduler [`#1725`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1725)
- Revert "PlexNotifier: Fix calling KODI notify instead of pmc" [`#1723`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1723)
- Feature: Scheduler: Redone [`#1722`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1722)
- Revert "Check getURL response before return" [`1387dd7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1387dd7795079de26bf198f1dc5bf3ad0fbf861e)
- Bring gzip out into config.ini as "web_use_gzip" for FR #1156 [`a0ba6d1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a0ba6d10c4470a6f5a614b43a9fc35856fc0aeb9)
- Revert "Remove hardlink and symlink from actions if Win32" [`da0cea0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/da0cea0468dffa429566c84e0a1ca7379685351f)
- Don't display paused show in backlogOverview [`85d36ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/85d36ca855de672e5aac4cf2c0a3bc23274189d7)
- Revert commit 728b79f5db6fd6ead56b874c2a030dafc794e320 [`70a88ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/70a88ca047846f1367a8d54244a67cb477c5544e)
- Merge pull request #1721 from abeloin/abeloin-patch-pmc_fix [`1a3c28f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1a3c28f8c32dbfb07f3d3eca201a6cdad46be873)
- Merge pull request #1720 from abeloin/abeloin-hotfix-showupdate_fix [`72c403f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/72c403ff6bf3cb36679922a10d9cb03060cac642)
- Merge pull request #1720 from abeloin/abeloin-hotfix-showupdate_fix [`345541e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/345541ef6313f8f5d7ff45ef84647d44a2c29304)
- Fix wrong variable assignation [`0458a2d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0458a2d1461e8bd81d885bdf4cdc7dd68c3d9744)
#### [v4.0.15](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.14...v4.0.15)
> 5 April 2015
- Changed showupdate to datetime.time when updating config [`#1716`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1716)
- Wrong value for change_SHOWUPDATE_HOUR [`#1715`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1715)
- Scheduler: apply the try on the whole run function [`#1714`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1714)
- Fix no title when submitting errors [`#1713`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1713)
- Fix freuqency in start queue [`#1711`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1711)
- EZTV: Fix missing import [`#1712`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1712)
- Added check in manual postprocess to remove hard/sym links in windows [`#1710`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1710)
- Remove white spaces from add show search string [`#1704`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1704)
- Remove access to settings backlog days [`#1709`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1709)
- Relocated coming_eps_missed_range to user interface in UI [`#1708`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1708)
- Providers: Revert _get_title_and_url [`#1707`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1707)
- RarBG: Add new search strings to catch error response [`#1706`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1706)
- Add show dir to log message [`#1692`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1692)
- Add Network Logos [`#1702`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1702)
- removeWords: Move into provider generic.py [`#1703`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1703)
- rtorrent: Fix encoding issue in windows [`#1701`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1701)
- KAT: Added removeWordsList to remove ending group [`#1700`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1700)
- RarBG: redone using api. [`#1698`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1698)
- submit error: if no title, use default one [`#1697`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1697)
- XEM: Skip invalid entries [`#1696`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1696)
- Redone showupdate in saveGeneral [`#1695`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1695)
- Fix default delete episode in GUI [`#1694`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1694)
- Fix episode description decode error in calendar [`#1682`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1682)
- Patch tntvillage season pack manage [`#1688`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1688)
- add qbittorrent sync file extention to ignore list [`#1687`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1687)
- Use T411 API instead of web scrapping [`#1685`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1685)
- Make removed episodes status configurable [`#1650`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1650)
- tntvillage: Cleanup [`#1677`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1677)
- Fix torrent empty in multi-episode [`#1684`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1684)
- KAT : enclosure season search with " when searching for season number [`#1681`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1681)
- anidb: add log line for editshow [`#1672`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1672)
- rtorrent: Provide traceback in log when torrent failed to send [`#1679`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1679)
- Normalizing Line Endings [`8795d77`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8795d77a9cb1f20a264b1f24765c85a4352364b5)
- Normalizing Line Endings [`e28f73f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e28f73f73048ce2e2a6c8a13aab0aa5ac7915c27)
- merge [`8435123`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/84351236d08146413a887c6d955ab5cfd4258a48)
- Fix freuqency definition in start queue [`cf9d794`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cf9d7945ca38e857807c7ce3d2d992f93138b1a4)
- Fix unicode error in verify_freespace [`3fa5a11`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3fa5a11ff55c26279027b894e291d22c7e14db35)
#### [v4.0.14](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.13...v4.0.14)
> 29 March 2015
- Update changes [`#1671`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1671)
- Add DEBUG setting to UI [`#1669`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1669)
- Add note to PP Extra scripts settings [`#1668`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1668)
- Restart showupdater thread when changing update hour [`#1659`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1659)
- Trakt: Catch all internal server error and log a warning [`#1662`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1662)
- Prevent seeing debug and db log in viewlog when debug=0 in config.ini [`#1661`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1661)
- Password encryption switch to v2 [`#1666`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1666)
- Updated network logos. [`#1667`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1667)
- PostProcess: Fix lower quality, bigger sized file overwriting current episode. [`#1663`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1663)
- Normalize all the line endings [`#1665`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1665)
- Fix torrentname with special char [`#1664`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1664)
- Fix inc_top.tmpl loading unnecessary stuff when not logged [`#1658`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1658)
- Hide proxy_indexers when proxy_settings is empty [`#1656`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1656)
- Remove jwplayer feature [`#1655`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1655)
- Fix gitignore issue with relative folder [`#1654`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1654)
- Add show: fix improperly decoded utf-8 characters [`#1652`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1652)
- Handle Trakt URL error code 500 [`#1653`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1653)
- Added anime regex for 003-004. Show Name - Ep Name.ext [`#1645`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1645)
- fix trending blacklist management [`#1637`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1637)
- Fix don't display prev and next airs if date is invalid [`#1648`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1648)
- PP Airdate: Check without season 0 first [`#1649`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1649)
- Fix active status on home accordingly to manage rolling download enable/disable [`#1640`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1640)
- tntvillage provider cosmetic fix [`#1646`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1646)
- Ability to ignore embedded subtitles and layout fixes in config_subtitles.tmpl [`#1617`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1617)
- Change removed episodes status from IGNORED to ARCHIVED [`#1643`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1643)
- Various fixes. [`#1639`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1639)
- Hounddawgs: Various fixes. [`#1636`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1636)
- EZTV provider [`#1561`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1561)
- Various fixes [`#1634`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1634)
- Added Default Info Language in general settings [`#1633`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1633)
- Manage rolling download [`#1453`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1453)
- home.tmpl: Fix search show name [`#1631`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1631)
- Update CHANGES.md [`#1630`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1630)
- PostProcess: Fix lower quality, bigger sized file overwriting current [`e4348a5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e4348a51c7694d36b8cc0754908471391c0d9e97)
- Defined default_watched_status in order to set it on watched episode [`ae82dfd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ae82dfd36c0a8736b91e4e74bc4e7ede7d606941)
- Managed the Unaired episode according to the rolling download criteria [`6c0543b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6c0543b25c135756bc1fe4615c88914754c7d241)
- blacklist existence check on trakt [`ac105e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ac105e1ef93bd76fb5f1f86d2d028f9213634443)
- Revert "Remove traceback from showupdater" [`0245e7e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0245e7ec675a2707745af91ca103a6638ea060f8)
- Fix verify_freespace to check show location and check old file exists [`0cd0408`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0cd04080fc057d17d991eb249907dc6b3c825ba6)
- Fix unfriendly log [`179414d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/179414df01fa7025f28a1880980e0b02c27c2a3d)
- Fix small bug [`330f473`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/330f473f3b610bbedd71d38be59746ee48c2f8bf)
- Fix small bug and changed the episode status for which chande to default_watched_status [`78fa1ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/78fa1ca997a6279e2c4beb3ad9f6db3dad649463)
- Removed unuseful check [`5f2033e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5f2033ee74a529db705601142ed4b2376304f78b)
- Fix check [`8b278b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8b278b3b6023c1b47138b69df96260a6570aeb45)
- Fix variable name [`a15325e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a15325ef1aa029baa9b17185de7bd4b180d8ff23)
#### [v4.0.13](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.12...v4.0.13)
> 22 March 2015
- Move encryption_version to the first item read from the config. [`#1627`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1627)
- properfind: Fix forgotten content [`#1626`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1626)
- Removed Fanzub [`#1624`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1624)
- Fix properfinder not starting or stopping when status changed. [`#1620`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1620)
- GlypeProxy: Fix identation [`#1619`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1619)
- comingEpisodes: Added js logic for forceupdate [`#1618`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1618)
- Proxy: Add a check for theGlypeProxy ssl warning for providers proxies [`#1616`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1616)
- Remove hardlink and symlink from actions if Win32 [`#1612`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1612)
- DisplayShow: ManualSearch ask if failed and/or download current qual [`#1613`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1613)
- Fix subliminal not working properly on Windows. [`#1611`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1611)
- home.tmpl: Fix loading show js error. [`#1610`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1610)
- Disable "Find Propers Search" if its disable [`#1609`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1609)
- Fix HDT proper/repack search [`#1608`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1608)
- Re-arrange items so proper settings can be together [`#1607`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1607)
- T411 - Add subcat 639 (tv-show not tv-series) [`#1604`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1604)
- Minor adjustments in editshow [`#1603`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1603)
- Added status column for subtitle. [`#1601`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1601)
- Added the ability to choose displaying columns in home.tmpl. [`#1600`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1600)
- Add workaround for improperly cleaned scgi over unix domain socket URI [`#1599`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1599)
- Fix "mass edit" subtitle enable action [`#1592`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1592)
- Add message about TVRAGE not support banner/posters [`#1593`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1593)
- Add Log directory to config page [`#1595`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1595)
- Remove newline from Python Version info [`#1596`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1596)
- Fix network sorting with comingEpisodes.tmpl [`#1588`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1588)
- Fix network sorting with small poster, banner in home.tmpl [`#1587`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1587)
- Add note to reminder user to add quality pattern in PP renaming [`#1583`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1583)
- Fix Trakt date and remove bad shows from recommendations [`#1579`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1579)
- Add coming ep missed range & Fix sab_forced addtion [`#1586`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1586)
- Add option to use force priority in SAB [`#1584`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1584)
- Add apparmor profile. [`#1405`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1405)
- Support for Foreign Releases based on Show Language [`#1570`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1570)
- Remove tvcache traceback and change to DEBUG [`#1575`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1575)
- Add upstart init file [`#1556`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1556)
- Fix restart page [`#1574`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1574)
- Fix HDTorrents [`#1572`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1572)
- Fix providers urllib quote and fixing title in log message [`#1573`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1573)
- Add 'tp' (Beyond TV) to mediaExtensions [`#1571`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1571)
- Show warning message to enable git reset or stash changes [`#1550`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1550)
- Hotfix - Remove BTFailure and add Exception [`#1565`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1565)
- Changed failure handling in PostProcessing [`5d8ce08`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5d8ce0894134f1a7a7929cc6045ae23a3c9b5d86)
- Possibility to blacklist show in trending [`97cbf8d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/97cbf8dbc523aeae4bbaa843aea2f9fed3f511f9)
- Remove bad shows (title is null) [`1214a95`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1214a9537d6b9274db4ba9fcdf16e0d9d038802d)
- check if release is valid for given show language [`d6f8fd8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d6f8fd8d95876493bc4f9b690f3250347da0f4eb)
- Option to not delete empty folders during Post Processing [`36b3a2f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/36b3a2f6858f9711a2ebfdae48b8e0f258c90cc2)
- additional quality matches for foreign releases [`0cdb0f8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0cdb0f8054aaf1f8b4254cb42cd87b7b05cb2101)
- Re-arrange items so proper settings be in sequence [`5b981ae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5b981aeb695e2540b12f846e96ac03552a1c7642)
- Fix incorrect indentation [`476c546`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/476c546ed9875dd9d22a19e3932d332e6de66f5f)
- Update Wombles for tv-x264 and tv-dvd [`3ec7eba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3ec7eba85bf6e85a398c41f05da1b90c561e1907)
- Fix broken sab_force addition [`3c2c874`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c2c874e7b0b0fa522e2328725c2e28bb201031f)
- Fix default new special status [`0f26da4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0f26da4b5e4057c9b0445a0c8190c6c3c49ff661)
- Revert "Fix "mass edit" subtitle enable action" [`24a6bfd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/24a6bfd7a3301350906e50c1cd622d6f4fe45c51)
- Update config_postProcessing.tmpl [`22a559b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22a559bd638002ab294dcf507222d12592f11c7a)
- remove ignored words [`23ae493`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/23ae493df7dfc31c98b93e7bdf4250a7bc21dd3e)
- re-order the allowed executables. [`cb120aa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cb120aad7b7bf36265bb2396a1faa765bc4d96b8)
- fix indentation. [`dd4c7e0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dd4c7e0516c69e9efea649aed921fd83affdf5c2)
- Revert "Fix low quality snatch not showing in backlog overview" [`e0ca8c0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0ca8c00d29baf3c2f4981d24d81e7dc089da323)
- Change traceback to repr(e) and DEBUG [`2a1c357`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2a1c357344fe7e3c7bc36e141dc85be93bdc1612)
- Fixed all episode in season search [`1ba2305`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1ba23051cb601a2e8ee6f4296776e26a9c2a441f)
- Fix List_associated_files checking wrong folder [`28c3ea2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/28c3ea21ee3e2cce83b8da24d17539a146755fae)
- Remove newline from Python Version [`db8fc5d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/db8fc5dfb05fe26dea6cf88cc47432874ac68c4a)
- Don't show webroot if is not enabled [`1111b2f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1111b2fa97bee482b5ae3b1b77698aaa1bf45f81)
- Hide subtitle setting if subtitle feature not enabled [`922d485`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/922d4852221d85b3ffd2b32f29aee826df462e48)
- Use date preset to show trakt first aired in recommendations [`0a96318`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a9631819de4dc2c6b36dbf86c8b565efc40a584)
- Replace space with dot. [`ace2907`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ace290763fbb8ed422e0fcc873cca5fe92b7f448)
- Replace space with dot [`a18cd0d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a18cd0d3369e2c0580706a7de61c38b41152570a)
- Replace spate with dot [`7deefea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7deefeada6847934d3ea01364c7a2b1324be8ed8)
- Changed unwantedfiles to str(unwantedfiles) in loghelper call [`1725bd4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1725bd4834885e3b7aeeddf6f08a60558997bed3)
- allow '/bin/cp' execution. [`0252a35`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0252a35d87bd85e9edfe4899137e8588ef5d55fb)
- allow git-remote-http. [`4eca33c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4eca33c1e1b71575488a9f50c2ccd3b310a9e05c)
#### [v4.0.12](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.11...v4.0.12)
> 15 March 2015
- Update set status description [`#1564`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1564)
- Change tvrage error to warning [`#1563`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1563)
- IPT: Redone findSearchResults forcing search in eponly mode [`#1558`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1558)
- Output more info when unable to parse bencoded data [`#1562`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1562)
- TorrentDay: Improved logging [`#1559`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1559)
- Fix deluge client not working [`#1557`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1557)
- Added some missing network logo's. [`#1554`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1554)
- Add hint to log search field [`#1553`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1553)
- Disable legacy import in config.tmpl [`#1551`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1551)
- Remove space from log lines (pre tags) [`#1549`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1549)
- Add Note to Post Processing config [`#1538`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1538)
- Submit: Limit the title to 1024 chars. [`#1543`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1543)
- Fix various providers issue in webui [`#1542`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1542)
- Added Kaerizaki-Fansub regex [`#1513`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1513)
- Disable daemon mode in MAC [`#1537`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1537)
- Backup when auto updating [`#1532`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1532)
- Fix re-raising issue to show the real stack trace. [`#1534`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1534)
- Added WebSafe filter to log viewer. [`#1530`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1530)
- Fix submit issue not reading all log files [`#1523`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1523)
- Remove traceback from showupdater [`#1509`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1509)
- Update torrentday url [`#1519`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1519)
- Add SR user and locale to /config page [`#1524`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1524)
- Don't show paused shows in backlog overview [`#1512`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1512)
- Send user locale when submitting issues [`#1518`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1518)
- history-television [`#1517`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1517)
- unrar: change the error message to be more helpful. [`#1521`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1521)
- Abort update if remote has new DB version or PP is running or showupdating [`#1491`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1491)
- rarbg: switch to request library [`#1503`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1503)
- Added use of global proxy in tvcache.py/getRSSFeed [`#1502`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1502)
- Try to fix invalid date in coming episodes [`#1501`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1501)
- Fix mede8er xml declarations [`b4023c8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b4023c835641c8241c7f72cd0ce5dbed74012346)
- Use consistent behavior in word filtering (global and show settings) [`3f35e94`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3f35e9462153c5048d001adf0aeb657490c6597b)
- Remove traceback errors when show is being update [`571e3f2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/571e3f2581484b7852fc0a70aa6d4e90c95973b8)
- Fix error 32 file in use when rotating logfiles on windows [`cf00c20`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cf00c207ebf99404418dc8948a551201bbef8192)
- Update torrentday new url [`7224719`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7224719a0bd4f359cf6ee744152b399d7d10782f)
- Fix deluge move completed default value [`646a309`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/646a3092813aa2bd22bbe908951a81a5b9ec7ebe)
- Fix for trying to process hidden sub/sub folders [`e5d5e0a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e5d5e0a052f6eaa65cefa078db9bf8ea3264c8e2)
- Fix error 32: file in use on logrotation on Windows [`50e3f29`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/50e3f2935f20f3cbdf1f53f5cb33d1d7f1acc84e)
- Disbale legacy import in config.tmpl [`1bf632a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1bf632a2681935667c2be234289b6b0b90f2a47f)
- Changed limit to 1024 as per GitHub specs [`703d6c6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/703d6c6dd3c1d9bd1721617c692d3d342c7cb7ee)
- Fix a none type in post process [`a23364f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a23364f6e0e074c9f5b31421bf2a6a7e54cb584c)
- Fix mede8er rating info [`9794254`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/97942542a4d8373e16132cf491a544fa960c850e)
- Change update restart page to restart.tmpl instead of restart_bare.tmpl [`f644e2c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f644e2c75bf2f258e978014c6c83b213190d22f2)
- Fixed a whoopsie in the naming of Wanted [`d796e2a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d796e2a81d4641ca4e44a86b3ef82adb8ea3c4c4)
#### [v4.0.11](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.10...v4.0.11)
> 8 March 2015
- Revert commit 76c8643a6e8c6d0aae6272b2539191916b5c0067 [`#1499`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1499)
- Check if $gh_branch is None [`#1498`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1498)
- sync watchlist fix [`#1486`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1486)
- Shutil: Catch error in finally when files don't exists [`#1490`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1490)
- Workaround for invalid date(eg 2915) [`#1487`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1487)
- Fix git password not encrypted [`#1483`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1483)
- Fix brackets in UNRAR log message [`#1482`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1482)
- Fix RSS search element name [`#1479`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1479)
- Fix list branches [`#1474`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1474)
- Change DIV message when list branches is empty, [`#1471`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1471)
- Sync Watchlist for event that has been lost for traktv site problem [`#1466`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1466)
- Added TRAKT_REMOVE_WATCHLIST Function as was before [`#1467`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1467)
- Fix submit issue. [`#1472`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1472)
- Shutil: Fix compatibility with Python 2.6 [`#1469`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1469)
- Don't check SSL certificate when fetching DB version [`#1470`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1470)
- Monkeypatch shutil.copyfile [`#1308`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1308)
- Force Show Information Update on snatch [`#1375`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1375)
- Fix coloring episodes as good when "archive first match" selected [`#1460`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1460)
- Add BinSearch to NZB Providers [`#1410`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1410)
- Sync wathclist [`#1400`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1400)
- Fix traktv season object merge [`d1997d1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d1997d1597bfac963c189e086c8d201ce1ad7585)
- Faster code to create trakt post data [`3fa97cd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3fa97cd2602c4be5667dc2897981bca9c402eace)
- Change viewLog to use rolled over logfiles [`5ce3134`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ce313446258270e4d12eccf26e361b1202154e1)
- Replace shutil.filecopy [`1dbf53e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1dbf53e49090c5dcdc090d36f3fdacae1c6f76f2)
- Moved trakt_post_data_merge from helpers.py to notifiers/trakt.py [`3c01d6a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c01d6a06f4ae2010bfd7aa42c2883c0d342b509)
- Redo metadata assignments for mede8er [`e18a8f2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e18a8f22977b1f5870db0b7b2eb2d9f98295dfd1)
- Fix some bug [`6425939`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/64259396533af0a73c36038493978bee5cc616ba)
- Removed unnecessary debug log [`b41710e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b41710e1c684b50274d0daae33345d5f7522246b)
- Disable checkout button when list branch is empty [`80d686b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/80d686b0c4d5690a6d60e7e69e7d1d417a55d763)
- Revert "Change DIV message when list branches is empty, " [`8fb971f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8fb971f61605bc422cb43b9f02d7f1bc6faa8445)
- Reverted commit a8787bc0d35990d47eee99e21c20689b6676b0b6 [`132f2f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/132f2f635cdcc68a812fc0df2721a74c77411a7f)
- Fix for PP always returning "Problem(s) during Processing" [`6ba75fd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6ba75fd674dbefc58d8780a74df4018c4af60121)
- Change list_associated_files [`5c3a536`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5c3a536d86a6c85f2b6b4ac7fc5f929c3f8788f0)
- Fix to not call list remote twice [`e40c00c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e40c00cc86584a988593ee860aee2964518dfaf4)
- Update tv.py [`81adf88`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/81adf882617f94c4fed20ca0fa270569bc943f54)
- Manage downloaded status and corrected failed status management [`bcf961f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bcf961fbb50a15369de2352e8f892c579bf76d86)
- Fix unable to add torrent rss when nzb search is disable [`08279f2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08279f2859adcb14e2ed251c5722d8756c247668)
- If checkout list branches is empty, change DIV message [`0c04ed8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0c04ed8621ab6a0ad4094f2fccf7cf0db7105787)
- Clean Up [`b17b6e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b17b6e2928e5a071c5ab47528a53d7e150d31623)
- Forget to popilate managed_show and minor fix [`78953cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/78953cb73cb2b3a04dd208b74f7e2112c9101c9a)
- Update tv.py [`3ef76a1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3ef76a179a3bfab47360a82ad27e9a8f26372720)
- Forgot to remove comment [`a614e80`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a614e806a0892a9627b4e494222b45a6c94dcb9e)
- Possible Fix for Pushbullet update notification [`138340f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/138340fadd055a1ed92584b903efbb8430451394)
- Fix shutil import error [`90bf896`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90bf896238e22d6863f1a1824457355620a3a0ae)
- Removed one epty line [`a55d084`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a55d0849088cb50f33c51db5ea6a84c9caedf360)
#### [v4.0.10](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.9...v4.0.10)
> 3 March 2015
- IPT: force eponly search since as it isn't supported by the provider. [`#1424`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1424)
- SCC: Fix season search only in sponly [`#1425`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1425)
- Trakt: Catch error when trying to delete library. [`#1463`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1463)
- Email notifiy: Fix msg created witout MIMEext [`#1462`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1462)
- Fix add newznab provider. [`#1461`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1461)
- Compare remote DB versions with local before update [`#1458`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1458)
- Added backup when updating [`#1459`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1459)
- Add "Use failed downloads" to search settings [`#1434`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1434)
- Fix pyUnrar2 on bad archive [`#1451`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1451)
- Remove traceback from generic.py [`#1456`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1456)
- Added some missing network logos. [`#1450`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1450)
- freshontv: Limit number of pages for RSS search [`#1452`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1452)
- Fix missing en_US not working in certain linux system. [`#1447`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1447)
- Update default trakt timeout [`#1449`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1449)
- Redone restart.js [`#1445`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1445)
- Fix viewlog.tmpl [`#1444`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1444)
- Check for UnicodeDecodeError in Cheetah's Filter [`#1442`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1442)
- Add a warning when gh object is set to None [`#1443`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1443)
- Fix time display for fuzzy dates with trim zero and 24 hour time style [`#1433`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1433)
- Don't use sickbeard.SYS_ENCODING for Cheetah's Filter [`#1436`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1436)
- Change File Date: Fix set date/time to local tz when local is chosen [`#1428`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1428)
- Restart: Fix timeout on get error [`#1435`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1435)
- Enhance RARBG [`#1421`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1421)
- Subliminal: Fix ogg subtitles track with und language [`#1427`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1427)
- Updated network logos. [`#1429`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1429)
- smtp: Added missing date field in email body [`#1426`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1426)
- Fix changing episode scene number not updating the show's episode cache. [`#1422`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1422)
- BTN: Fix searching in season mode for episode [`#1423`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1423)
- Fix color in displayShow when manually searching. v2 [`#1392`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1392)
- Check actual branch before switch [`#1414`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1414)
- Don't remove logs folder when git reset is enabled in UI [`#1390`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1390)
- Subtitles 3/3: Suppressing subliminal logs on windows [`#1388`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1388)
- Subtitles 2/3: Subtitles: Path always in unicode [`#1387`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1387)
- Subtitles 1/3: Windows UTF-8 console via cp65001 [`#1385`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1385)
- Change the language dropdown in editShow.tmpl [`#1416`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1416)
- Add a missing urllib3.disbale_warning() [`#1409`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1409)
- Replace language selection in add show. [`#1393`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1393)
- New Feature - Log search and log filter by SR thread [`#1347`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1347)
- Fix PR #1403 extra ) [`#1404`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1404)
- Urllib quote keyerrors issue #708 [`#1403`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1403)
- Handles multi-page results and improved login [`#1395`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1395)
- Added network logos. [`#1402`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1402)
- Added a specific regex for horriblesubs [`#1386`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1386)
- Provider SCC: Catch exception on getURL [`#1389`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1389)
- Updated network logos. [`#1381`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1381)
- Added missing network logos [`#1383`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1383)
- Remove trademark from filename [`#1370`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1370)
- Possible fix for kodi notify [`#1371`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1371)
- Update T411 to its new domain name [`#1376`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1376)
- Possible fix for ValueError: invalid literal for int() with base 10: 'un... [`#1377`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1377)
- Add SD search to RARBG provider [`#1368`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1368)
- Opensubtitle - show only error message not traceback [`#1348`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1348)
- OldPirateBay: Replaced url tv/latest [`#1366`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1366)
- Trakt remove traceback [`#1363`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1363)
- Added network logos for Canada addikTV and Séries+. [`#1356`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1356)
- AniDB: Fix generating exception on timeout in PP [`#1339`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1339)
- Restore: Replace os.rmdir to shutil.rmtree [`#1364`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1364)
- Remove blue color from 100% progress bar [`#1354`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1354)
- Add value to TNTVillage self.hdtext parameter [`#1352`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1352)
- Fix backup issue with invalid restore folder [`#1358`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1358)
- Fix navbar not collapsing properly [`#1351`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1351)
- Fix self.hdtext declared as list instead of dict [`#1349`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1349)
- Reworked the backup/restore to properly handle the cache directory [`#1345`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1345)
- Added TNTVillage provider [`#1311`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1311)
- Added support for Plex Media Center updates with Auth Token. [`#1340`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1340)
- Hide submit errors button if no git user/pass and auto submit [`#1342`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1342)
- Fix for RARBG provider [`#1343`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1343)
- Disable urllib3 InsecureRequestWarning [`#1341`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1341)
- Add RARBG provider [`#1338`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1338)
- Trakt: Catch all requests exceptions [`#1330`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1330)
- Updated network logos [`#1332`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1332)
- Improved logging to detect CloudFlare blocking [`#1326`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1326)
- Updated network logos. [`#1325`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1325)
- Added new regex 'itunes' [`#1296`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1296)
- Rtorrent client improvement [`#1244`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1244)
- Fix if in wrong position [`#1324`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1324)
- Modified sanitizeSceneName() for anime exception. [`#1323`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1323)
- Fix subtitles display issues. [`#1322`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1322)
- Fix travis build status image in readme [`#1154`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1154)
- Fix typo for locale from us_US to en_US Part 2 [`#1321`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1321)
- Separate providers for oldpiratebay and thepiratebay [`#1270`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1270)
- Revert commit 32da0199f2690b8b04349ebd495c6a7ad5a2b2f4 [`#1318`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1318)
- Updated login param value for torrentBytes provider [`#1317`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1317)
- Fix misc issues [`#1315`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1315)
- Update init.debian to exit instead of return when 'restarted' [`#1312`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1312)
- Fix typo in displayShow.tmpl [`#1307`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1307)
- Fix progress bar vanishing when shows table empty. [`#1306`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1306)
- Fix unknown quality [`#1303`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1303)
- Added default host:port for each torrent clients. [`#1302`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1302)
- Modified touchfile() to detect ENOSYS and EACCES. [`#1295`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1295)
- Fix incorrect operator in dailysearcher.py [`#1293`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1293)
- Disable ssl checking in synology client [`#1289`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1289)
- Added detection of fs not implemented link creation [`#1287`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1287)
- TVRage, TVdb: Check if show has episodes [`#1285`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1285)
- Fix issues with newznab provider [`#1283`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1283)
- Fix for uTorrent 2.2.1 token order. [`#1282`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1282)
- Corrected aspect ratio of Sky Atlantic network logo [`#1279`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1279)
- Fix verified status of torrents from KAT [`#1278`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1278)
- changed subcategories order [`#1277`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1277)
- Always sort last by asc name in shows table. [`#1276`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1276)
- Improve code check for list comprehensions on subtitle [`#1275`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1275)
- Newznab Categories not beeing saved [`#1274`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1274)
- Trakt 2.0 API fixes [`#1269`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1269)
- Fix case issue for accesstoken [`#1268`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1268)
- Fix IPTorrents url. [`#1267`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1267)
- Use https://kickass.to/ instead of http://kickass.so/ . [`#1264`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1264)
- use subprocess instead of os.system [`#1262`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1262)
- Improve code check for list comprehensions [`#1260`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1260)
- Fix GitHub submit error [`#1233`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1233)
- Fix if network is None for ical [`#1230`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1230)
- Fix accent issue on system with locale like POSIX. [`#1224`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1224)
- Updated torrentday URL [`#1207`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1207)
- Temporary fix for Python 2.7.9 for SSL [`#1304`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1304)
- Change cookie name to prevent name collision. [`#1290`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1290)
- Generate a cookie instead of using an hardcoded one. [`#1320`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1320)
- Fix 'first_aired' date parsing [`#2`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/2)
- Fix access to webcal without password. [`#1234`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1234)
- Add notice in addShow for special with TVRage [`#1235`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1235)
- Try to fix issue #258 [`#1238`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1238)
- Update to Trakt.tv API 2.0 [`#1241`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1241)
- Remove an extra apostrophe from content-type. [`#1242`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1242)
- Fix moving files across partition [`#1243`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1243)
- FreshonTV now supports HTTPS [`#1245`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1245)
- Change color of 100% progress bar light theme [`#1249`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1249)
- Set UNKNOWN quality as Low Quality [`#1250`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1250)
- Added custom rpc url for transmission [`#1256`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1256)
- Updated iptorrents URL [`#1208`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1208)
- Fix 'Sort with "The", "A", "An"' on dropdown in displayShow not working. [`#1217`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1217)
- Update unrar2 from 0.99.3 to 0.99.6 [`#1220`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1220)
- Fix absolute numbering used in notification. [`#1221`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1221)
- Fix issue when location is empty and there's no len() [`#1213`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1213)
- Fix wrong icon used in Growl notification. [`#1214`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1214)
- Fix versionchecker [`#1212`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1212)
- Updated Kodi icons [`#1216`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1216)
- Fix jump to select season dropdown list not working. [`#1215`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1215)
- Patch country flags [`#1210`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1210)
- Fix no attribute while search for proper. [`#1209`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1209)
- Re-download episode when manualsearch and quality is Unknown [`#1206`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1206)
- Check if list_remote_branches is empty before for-loop [`#1203`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1203)
- Mass update: Add option for default episode status [`#1201`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1201)
- Fix Safari next show button not working. [`#1200`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1200)
- Update TODO.txt [`#1196`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1196)
- Fix default episode status in display and edit show. [`#1197`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1197)
- Search Providers: Remove Tvtorrents [`#1199`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1199)
- Feature: Add IMDB ID to show webapi [`#1183`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1183)
- Fix low quality snatched episode don't appear at backlog [`#1184`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1184)
- Updated qtip to 2.2.1 to fix tooltip not showing. [`#1187`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1187)
- Adding a download field for the episodes [`#1186`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1186)
- Removed console logging in ajaxEpSearch.js [`#1188`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1188)
- Patch jquery bwlists [`#1189`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1189)
- Added support for Plex Media Center updates with Auth Token. [`#1190`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1190)
- Fix jQuery live not working with 1.9+: [`#1192`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1192)
- use os.system for file copies on posix systems [`#1193`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1193)
- Ignore unrar executable on Windows. [`#1194`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1194)
- SiCKRAGETV/sickrage-issues#360: remove globals in post processing code f... [`#1195`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1195)
- Fix for https://github.com/SiCKRAGETV/sickrage-issues/issues/178 [`#1182`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1182)
- config.clean_url may add trailing /'s in unsuitable circumstances. [`#1180`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1180)
- Fix for SiCKRAGETV/sickrage-issues#360: remove globals in post processin... [`#1179`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1179)
- Fix issue showing 'unknown dir' when adding shows [`#1178`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1178)
- Postpone Processing for incomplete torrents. [`#1176`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1176)
- Fix multipart rars causing the same extracted video to be postprocessed more than once [`#1175`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1175)
- fix for SiCKRAGETV/sickrage-issues#347 [`#1174`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1174)
- Auto send user and password when open managetorrents page [`#1171`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1171)
- Implementation for sickragetv/sickrage-issues#322 - Add extra progress-bar color for when show is fully downloaded [`#1168`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1168)
- Add Free Mobile SMS Notifier [`#1165`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1165)
- Backup/restore: include cache directory [`#1164`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1164)
- .gitignore - ignore cache folder and not just the contents [`#1163`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1163)
- Don't clean user files when GIT CLEAN [`#1162`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1162)
- correct jquery syntax to select value to fix issue #285 [`#1160`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1160)
- Network logos updated. [`#1159`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1159)
- Don't re-download same quality if we do MANUAL SEARCH [`#1155`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1155)
- Update&add canadian network logos [`#1153`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1153)
- Update kodi.py [`#1149`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1149)
- Added search provider icons. Added network logos. [`#1152`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1152)
- Fix for issue #358 [`#358`](https://github.com/SiCKRAGETV/sickrage-issues/issues/358)
- Replace the language selection in add show. [`d8d4021`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d8d40215f70ac7f94345c4d7fd080d8e7047ffba)
- Fixed issues with newznab custom provider categories. [`0da960f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0da960ff51c4c13441bc6bbda36fd5c8efd75003)
- Updated Requests to 2.5.1 [`fb3cb22`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fb3cb2280863d6dfcd036c2cf2dfdf02ef094740)
- Dropped pastebin and switched to using Gist's for attaching logs to issue reports. [`0b35e9f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0b35e9f2fd7d64b3f770b4b20174d62bf7406fc2)
- Fix path issue with country flags. [`e7f7167`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e7f7167567f468856968df4e055b23ae1c465f11)
- Fix for sickragetv/sickrage-issues#178 [`9fedc24`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9fedc24c556c1b1ac02b7ecdc568a4cf054259d1)
- Updated OldPirateBay file list parsing [`a9ccfd0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a9ccfd0f6d2680865290081da8c3632754708c71)
- Fix subtitles display issues. [`3e1e3e6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3e1e3e61ff482226cdcabc03b4143124bd879585)
- Fix restart timeout on get error [`5835fff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5835fffa5ede940a140cd5d30019e8ece36da3c5)
- Changed Releasegroup handling in Renamer [`5088e06`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5088e06e28582654267cc02fdbde3ca508f14088)
- Reverted change torrentday.py, the shouldn't be included [`ccf3a03`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ccf3a03c24736103c962a950c6db06e47acca0cd)
- Fix for sickragetv/sickrage-issues#322 [`2830b9d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2830b9d83ee4dad25c9582e5ac322092b7776391)
- Made logging configurable [`e88e12f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e88e12f5d59a37613544856ad92aa0a923df9356)
- Removed 'page' parameter [`72826f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/72826f6dd274c8e53434acadfef221acb190776c)
- Make the timeout configurable [`7f5d0ff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f5d0ff375e17d2d4de4d923995d9929a0084562)
- Update webserve.py to compareDB on checkout [`384772b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/384772b4cfae58e3d647b536f31713ff2b48531f)
- sickbeard.config.clean_url may add trailing /'s in unsuitable circumstances [`82da317`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/82da3171cdf1e963fd72825aa50a6a97af0e6867)
- Update config.js to compareDB on update [`5eb6937`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5eb693777448cde8092a536bd90823a0fb9b86ed)
- Changes to fit new site layout [`4151cdf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4151cdf9b528d71bbf3471df1e39ffe41f9371be)
- fix for sickragetv/sickrage-issues#347 [`9aa28d1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9aa28d18d2d32819fecb4c0514195f2dd5825b8c)
- Clean up the trakt config section [`6b7a96a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6b7a96a13565ab36d06d3687ade501cea56bb3d0)
- Reverted wrong code commited [`3f2aa42`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3f2aa428c4ee492b50c3a5e1dc70b7d965042cb1)
- Removed some comment [`94853c0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/94853c0f27170e284c1492a3583758887bf5f29e)
- Remove blue color from progress bar [`2b1442b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2b1442bb6eca13498421590fe799a12592cbeb6a)
- Don't show the Download column when the download_url is not set [`53c9418`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/53c9418084a45903718ef48660747bef993b9088)
- Fix Black and White lists in edit show. [`7796f06`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7796f06b944512d811a2e0929cdf5930e379b2b8)
- Fix for sickragetv/sickrage-issues#303 [`f43bc62`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f43bc62936745f33aafe1b09bf7aed58c6d9d5fa)
- Fix set date/time to local tz when local is choosen [`b62c4f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b62c4f417cab2a387cfd605c30cb12d8771cacf1)
- Revert "Possible fix for ValueError: invalid literal for int() with base 10: 'un..." [`61d1e6f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/61d1e6ff6e75db198e655bb69ac4174d1fc06862)
- Possible fix for ValueError: invalid literal for int() with base 10: 'undefined' [`a61d8c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a61d8c7c2e688fe81716d8e7d37bff7b6ec191ad)
- Fix Proper instance has no attribute 'size' [`2985f61`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2985f61cce830a24f70a6f36b904ca30bde628ec)
- Fixed leading slash. [`b67ef81`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b67ef8133758d1a7565ecea4edbb0f6a51302b87)
- Fix for sickragetv/sickrage-issues#256 [`68e4aca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/68e4acaf3730a114ccabc9585d8958676257142d)
- Update readme.md [`ac153cf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ac153cf2320b3b6d0a8aa9a1b1646a51347581d6)
- Make sure we're returning the result of the recursive request [`9cfc3e3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9cfc3e378821e3ba5c8491137fb81dc1d839b8b8)
- Fix if network is None [`cee1566`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cee1566b7bda3da6a90e82954c0e397a6fe258e4)
- Update torrentday.py [`5032826`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/503282694c956ec959bfb8eb97af97dfd2343059)
- Fix for sickragetv/sickrage-issues#274 [`450a09f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/450a09f1a0482d6df6c36c79edbf816d631b88b2)
- Replace os.rmdir to shutil.rmtree [`774b5e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/774b5e2149f179d8ae77417e5318530ad218c963)
- Fix absolute numbering used everywhere if selected even if custom anime [`94732e9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/94732e9568f58b9f89330fec827ebc34671bb1d4)
- Fix for sickragetv/sickrage-issues#263 [`972ee14`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/972ee14216a6146e69fa909355791380d4c4e1bf)
- Use sbdatetime instead of self [`80ff343`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/80ff343ff255aa43ed0cf6c284d23a11502f1a5c)
- Fix .gitignore [`3b29658`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3b29658051707b6bf5808212b68d867249897da1)
- Use hostname rather than IP [`98d9235`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/98d923555ec13ea60eed03a6a1c8afff501a2a3b)
- Fix progress bar vanishing when show table empty. [`3917818`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3917818d6fa5a19ec3bc7245383e42f5ec98cd6e)
- Change the name from sickrage to sickrage_user [`6b1a4e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6b1a4e204a0d77a9f80f15f7a3de88c429519ec4)
- Catch exception if unable to cache the response [`c5cfede`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c5cfede6382a7a29356b3ceaa3f1513cb16f4fe0)
- Use shutil.move instead of os.rename to move file as os.rename doesn't [`2ef08d1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2ef08d1c256d65163290eb843de27b453eb27de3)
- Fix issue when location is empty [`1856966`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/18569665de7804140a11976f0ba7e10d37f34181)
- Update webserve.py to add delete_failed [`d48772b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d48772baa64f55cfe55c2956ec81ac8a115c5c6f)
- Check if we are on windows before query Windows version. [`53e67ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/53e67caea520f2b048e2f6a3ebcb38454e31a271)
- Fix downconverting path from unicode to str [`35c1761`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/35c1761a0159f96fc6667b595a3199c2e0d5d8d6)
- Prevent submitting empty gist. [`17545d9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/17545d93b2bf03fe2becbb89b32e578ab3ec13c6)
- Fix only generating the bwlists for the first item. [`10a199e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/10a199e62fecb44d184e16902e41b4789dd6ec5d)
- Fix msg created witout MIMEext [`df92cee`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/df92cee84eff9c6d630110f67ebc0df022d4b7a6)
- Fix viewlog [`ebb0c06`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ebb0c06c13a2a84de6cc967d5c5ca9a97c754c08)
- Update traktchecker - remove traceback [`646042d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/646042df8242dd9016c33f2b30b6e7d6665bd3da)
- Catch all requests exceptions [`ad29d18`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ad29d18bc0959d1117a4e024401cfb52d0ca6d67)
- prevent command injection [`1b3b109`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1b3b10903b8e3fec58941036b0084d9cd8e743dc)
- Fix for 'List type has no attribute' on setting failed [`9a3fec8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9a3fec811f32d7bff8dadbfe0ae0c5a51753f37c)
- Re-download episode when manualsearch if quality is Unknown [`8ad5292`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8ad52924a62e0fbf5fbeb04325487a642ff54cfc)
- Update helpers.py [`4122029`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4122029df677acc363ebadc51bdc13ea8042b71f)
- Fix time display for fuzzy dates with trim zero and 24 hour time style enabled [`4ea66cc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4ea66cc713d9c95f8cf12a3add4d8ea7ea3a2688)
- Fix low quality snatch not showing in backlog overview [`226a714`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/226a7148d267bf4548044b45aef40d444807834c)
- Format the rating in whole percentage [`a1871e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a1871e2d43ece9d85e1be98a5aca6c97b88b2686)
- Fix for sickragetv/sickrage-issues#178 [`8b84e4f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8b84e4f4bc6cdebdc605438e9e75d15f1133d65e)
- Fix typo in emailnotify.py [`f94f11c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f94f11ccc174ddedccbff2231fb97ff688809386)
- z [`7c957a3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7c957a3775575da1d628e2d5f29c543033602088)
- Don't use system.encoding for Cheetah's Filter [`91c35e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/91c35e1706ff6208e037d692caea3628b4161e6c)
- Fix Exception generated: Cannot find attribute 'contentrating' [`3a9f137`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3a9f137522feb6144e959fe93837bed6d02b5bf7)
- Fix rarbg provider searchstring encoding [`2ecf2e7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2ecf2e78ca01b084692c4718dafc9e841ab49410)
- Remove part of the condition to enable utf8 on Windows [`8c846d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8c846d75b7390067728a8482ea90114682e19639)
- OldPirateBay Replaced url tv/latest [`3ee18ff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3ee18ff279ef6832108ccd46dbacd9d58acb17d7)
- Update traktchecker - remove traceback [`74d49cc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/74d49cc2fd31dedb13b2cad86a20ca3cee95c6d9)
- Fix string [`4efb39c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4efb39ce87040bea8d596671598f71bbe306663d)
- Opensubtitle - show only error not traceback [`90cd0e0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90cd0e017a70fd99f0531f8874c0801820f50ee0)
- Fix compiling error [`4166099`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4166099c4ad95e96173a40ba9e882c3bf4a67858)
- try ti fix generic modification [`61e201d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/61e201d2010fa94104038652f158d8acee248a99)
- Fixes shows with double quotes [`aeef329`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aeef329bff80f4f2b64261e12c631792d6119b2b)
- Fix missing css tag for text color. [`7d3382d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7d3382dc075d441920a55f2fece6315e71b708ea)
- Revert "Fix low quality snatched episode don't appear at backlog" [`7b767c2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b767c27a90c3ce22c41134afb7c0b3e69d5f15c)
- Updated kickasstorrents URL to kickass.to [`1babd3e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1babd3ec3b5b6e639fa456effb6e4c0d40731290)
- Partial Revert 1253 [`c0aa41f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c0aa41fefa36782641d9a92a163a40b9031417b7)
- Update kat.py [`3509610`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3509610635f0113d3ecc1ad2571d6586a834b098)
- fix oops by not referencing ssl disable property on sickbeard ob [`3e8346a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3e8346a6831d0d20fd913629ff906309e079f89f)
- Use https://kickass.so/ instead of http://kickass.so/ . [`7e7cdb8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7e7cdb846f343a9f652ffd391e8227f3cb03da7e)
- Fix misplaced or to prevent Nonetype errors [`a3bb636`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a3bb636df27d9363ad4cde5ef0eeae77a5afab77)
- Remove an extra apostrophe. [`bb26790`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bb267905aaf07a5c52e4c2518207f7cf76d481fd)
- Update helpers.py [`2f9362c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f9362c74cbf4530a6af5341af3fecd8c1f21a1b)
- Fix wrong url handler [`0888942`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0888942820ce1a4131528f545d4ee8702cdf5f5e)
- Fix number of lines submitted. [`c9085a3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c9085a3ac667944301d628636e718a22b097a8eb)
- Forgot $sbRoot. [`9dc7bd1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9dc7bd1938f8e1be6777ff7d5a6492c9fd8be2f6)
- Update manage.tmpl [`639072f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/639072ff3ad94613b6d8de1901fafeb2f3d748b7)
- Fix jquery syntax to fix changing show [`1662e21`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1662e212fe71f34ac08dda7debbbb63f41b9a4bf)
- Removed print statement [`999767b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/999767b77e9d39c8662b578a1156cd64ee0ab864)
- Restored back previous Comedy Central logos. [`7f45514`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f4551468d8dfe21b46b110b30b3a628a025e637)
- Renamed network logo of séries+ to series+ [`27ac4ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/27ac4cad49b4eaee6f4e46d77d70a7515be26e12)
- Replaced white network logos with colored versions. [`5ed88f3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ed88f3fb0ac9343a3f6f15abf9a65cafe49121e)
- Replaced adult swim network logo with colored version. [`c35a4f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c35a4f961178ed52b0f17d178c6c46b5a21a839b)
- Merge tag 'v4.0.9' into develop [`c71085a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c71085ab3857994b1d9b363863af1134d4d066a4)
- Merge tag 'v4.0.8' into develop [`f224e41`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f224e413ff97cf9a248e5f59f49161eda3c30e91)
#### [v4.0.9](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.8...v4.0.9)
> 21 December 2014
- Fix for sickragetv/sickrage-issues#246 - Moved rls required/ignored words to pickBestResults function to occure before we filter the rls name for bad characters plus we now use this function when searching for propers/repacks. [`33e9587`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/33e95870e0c1b241c93f541d4ee27ed6ba3bfcb8)
#### [v4.0.8](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.7...v4.0.8)
> 21 December 2014
- Fixed issues with issue submitter and pastebin logs. [`3b37dc0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3b37dc054004b00dd2e2c1ada83c7ce7d8cf227e)
- Updated fanart api handler to use new v3 api scheme and re-coded metadata function to properly retrieve images including thumbs. [`46bd851`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/46bd8515c2c2c3d5c92a20712c42186eac347e34)
- Resized flags to 16x11 to correctly fit in language selector for subtitles. [`f2e3380`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f2e3380cb21d408b42672aae1ac2ea50368d70cc)
- Malformed airdates now raises a warning instead of a error so we dont clutter logs. [`482f20b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/482f20b735491337bacf689432412d356e70f78e)
- Git clean/reset performed before updates now if set from config to avoid update issues [`2d14eef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2d14eef522739becf994be696b190624692a1d6a)
- Fix for sickragetv/sickrage-issues#247 [`b667c72`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b667c722f2ff05975bde8fb1dec9579c3112beab)
- Fix for sickragetv/sickrage-issues#236 [`009da64`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/009da649751e8831afe5f845290487a303c03e60)
- Fixed sickragetv/sickrage-issues#229 - check instance of actor or banner obj to be list and if not we throw it into one. [`bac95b8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bac95b848b7f6e2a7512f1e4d8b1d695cc484331)
- Fix for sickragetv/sickrage-issues#249 [`60e97fb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/60e97fb3cc2192260ff3489be36f19d6b4efecf6)
- Fix for sickragetv/sickrage-issues#236 [`d08d401`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d08d401769aa509a33fc9d758176358cf30e4405)
- download_file helper function now decodes unicode on the fly [`76062ae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/76062ae2a7c502dc45ad031242139973f23ecc35)
- Updated flag images. [`b669195`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b6691958827dd9ac0400265f817095d3fad3ecf4)
- Fixed sickragetv/sickrage-issues#117 [`1044808`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/10448086383fc36683fd2eff41f6366890c6fbdf)
- Fix for sickragetv/sickrage-issues#237 [`885ef12`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/885ef128fc2aa50b5386143f937b647b435c09d1)
- Fixed sickragetv/sickrage-issues#117 - CensoredFormatter class func format code corrected. [`785ffdc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/785ffdcf2f58537cc47571e5c18cb954e9d0457e)
- Fixed sickragetv/sickrage-issues#238 [`d5f7a07`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d5f7a0719ef162ba6f8f3b5df78284f6bf1c3724)
- Fixed incorrect flag image files for subtitle languages [`15e6280`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15e62802ffd801ab5e5bd9a26cb441f6430f11c9)
- Replaced old poster and banner files with new custom sickrage poster and banner files. [`3829e34`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3829e341b2a49e8541bff7a7f89ffe415bb5b3d4)
- Merge tag 'v4.0.7' into develop [`11e12b9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/11e12b95d1a4e9ff778571b430d4aaa90cb89a75)
#### [v4.0.7](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.6...v4.0.7)
> 20 December 2014
- Fix for issue #216 [`#1148`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1148)
- Fixed sickragetv/sickrage-issues#205 - Getting a proper local lan ip [`2e13186`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2e13186256d31b494025579ea5c2cfe8197c79c1)
- Updated code for get_lan_ip to fix issues with returning local lan ip from network interface. [`8e9f4f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8e9f4f47cb1a3046f99ec0eaa6d2155d6f542765)
- Fixed issue with issue submitter deleting all errors before submitting them all. [`fb3d485`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fb3d485ced829950812cd764b81608b7927bb5cc)
- Updated code to added referer header for web proxies [`4e0a4c3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4e0a4c3f9998e42923015cf632ad2ba8b37579eb)
- Merge tag 'v4.0.6' into develop [`82f58c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/82f58c703a51d7c814da3ac467d61291f9baa900)
#### [v4.0.6](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.5...v4.0.6)
> 19 December 2014
- Possible fix for sickragetv/sickrage-issues#180 - redirect loop [`120ea96`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/120ea961f25814b1cb5e176a697eb2e69ab77d8a)
- Improved pastebin logs to search via regex and timestamps for error line then grab 50 lines of data before that. [`477938e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/477938e5f34599ff3c1f4119c90a0ade39425ec5)
- Fixed sickragetv/sickrage-issues#180 - this resolves redirect loops resulting from to many threads being open at once. [`0f4a539`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0f4a53919483b6ce4f206ab1b00306149627e1ba)
- Updated travel yaml file to annouce on new update channel #sickrage-updates [`2f4d3cf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f4d3cfe3c4d10aa61f80eb6c13eec071161e966)
- Fixed sickragetv/sickrage-issues#210 [`3b42cb6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3b42cb68f91e32c30c776cf0da11f11090fc9ac8)
- Merge tag 'v4.0.5' into develop [`2785abe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2785abe8a47b1fb45bb4fca6134e37b0a487dfff)
#### [v4.0.5](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.4...v4.0.5)
> 19 December 2014
- Updated piratebay.py with oldpiratebay.org urls [`#1146`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1146)
- Fixed home page issues. [`9927e8a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9927e8ad92401ba7e5f990c1d5f89bef43ed09b4)
- Merge tag 'v4.0.4' into develop [`6151062`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6151062ea45470e6f8793fb20275518490683635)
#### [v4.0.4](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.3...v4.0.4)
> 19 December 2014
- Fixed issues with pastebin attachments for issue submitter. [`476350a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/476350aa7afc279c7d89303479af816ae00baf79)
- Fixed issues with pastebin attachments for issue submitter. [`d881f79`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d881f794debbe192604407e29829e192c138996f)
#### [v4.0.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.2...v4.0.3)
> 19 December 2014
- Catches error from set file date and email when they have special charactors in them [`#1140`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1140)
- Fixed sickragetv/sickrage-issues#127 - added requests lib package to autoprocesstv folder then inserted it into path env [`6768741`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6768741cfe3ff43bde96cf395751988197fdb420)
- Fix for duplicate tickets being submitted via app, title variable was being appended to. [`f40d5e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f40d5e13102b1c1506e2c262f38ade7646eb08d3)
- Catch error when speical charactor crashes email send [`27daf8b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/27daf8b46cb79f6eb4546722e163b7b79abe42de)
- Catch error when setting file date [`ed0e7e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ed0e7e47168aa297458ead10b9f98d7e893f0aca)
- Fix for sickragetv/sickrage-issues#157 - force redirect to home if 404 http error. [`3060757`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/306075738113767b4623bb32eb36bad5cf05eeb8)
- Catch error when speical charactor crashes email send [`0030c87`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0030c87d044d45dfd36ca7e04249c64429388629)
- Fixed sickragetv/sickrage-issues#170 - checks if key 'language' is present if not discards. [`c65b17d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c65b17d09bf949b9ec348ba25dd866e60cdc3cbe)
- Fixed sickragetv/sickrage-issues#113 [`5e1298f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e1298f801648204fa62456e86d02bf53f61d1c5)
- Fixed sickragetv/sickrage-issues#175 [`88af4c9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/88af4c905a327c0c5d24e8df31459406767c8afd)
- Fixed sickragetv/sickrage-issues#162 - will always return list object even when branches do not exist [`ce78735`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ce7873584f26c2a85632bdb13ce14e8c8df59513)
- Fixed sickragetv/sickrage-issues#175 [`b27e8e8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b27e8e88a553a6434913b63c2648d6507bfae32e)
#### [v4.0.2](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.1...v4.0.2)
> 17 December 2014
- Fixed sickragetv/sickrage-issues#119 - IOLoop was being loaded before daemonizer code due to improper placement in WebHandler class, moved to init. [`ced8785`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ced8785269908bb6da8b51e8dd3d467de52adaf4)
- ErrorLogs now cleared after submission of issue ticket reports so that the same errors don't keep getting re-submitted with new ones. [`7b219fc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b219fce8fc257af05d99224f56f2df71de8fa7c)
- Update readme.md [`170d50c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/170d50c2798d122ac2e7f97d54230ecd7b9d993a)
- Fixed sickragetv/sickrage-issues#119 - IOLoop was being loaded before daemonizer code due to improper placement in WebHandler class, moved to init. [`086e7ab`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/086e7abf7009ae486c5e0850670563daf6fae222)
#### [v4.0.1](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v4.0.0...v4.0.1)
> 17 December 2014
- Update .travis.yml [`1b850b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1b850b3aaa7e62c325230b30517f16ca3350d52b)
- Update readme.md [`8302115`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8302115b6eeeb108494aeccbc6e648e0da277ac1)
- Update readme.md [`c99a8e6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c99a8e6565dc8ad6025d678abec05cb9f4128278)
### [v4.0.0](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v3.9.2...v4.0.0)
> 17 December 2014
- Added network icon for "The Hub" network [`#1143`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1143)
- Fixed Screenshot layout [`#1144`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1144)
- Re-add screenshots [`#1141`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1141)
- mediaToSickbeard.p fix to work with new login system, check for http status 302 [`#1139`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1139)
- Add kat url to the logo at Providers [`#1124`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1124)
- Added Crackle and El Rey Network logos [`#1101`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1101)
- Interface fixes [`#1052`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1052)
- webserve.py has no attribute 'MainHandler' [`#1039`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1039)
- Add removefiles to api show.delete [`#1035`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1035)
- Copy headers set in request handlers to main handler [`#1020`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1020)
- Add screenshots to readme.md [`#1008`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1008)
- Fix error in webapi causing "No Shows" in NZB360 [`#1005`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1005)
- added snatched episodes to shows.stats api command [`#995`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/995)
- Proper fix for EZRSS, issue #984 , previous fix actually totally broke EZRSS [`#998`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/998)
- Fix api/builder if your using a webroot [`#983`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/983)
- Add more info to api command show [`#973`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/973)
- Fix Provider Priorities tab when torrents disabled [`#967`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/967)
- Added features for web api [`#949`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/949)
- Added Smithsonian Channel and Esquire Network Logos [`#960`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/960)
- Add custom nzb category and torrent label for anime [`#961`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/961)
- Improvements made to tv cache code for providers [`589b716`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/589b7167c196ea5ff41315f915ab1ea6b28f3bdb)
- Fixed system path to prepend instead of append for custom libs [`44ae0c2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/44ae0c2933c2f360f6d338c4ee78d15bef72e5cf)
- Fixed issues with WebUI crashing when using a custom web_root setting in the config, also fixed a few other misc WebUI related issues. [`7213fba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7213fbac1164a826c5cbd9080dc7a30102cc098a)
- Re-coded logger facility for better performance and cleaner code plus has better code for rotation of logs. [`3eb366a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3eb366ac0598eed83d1932b64ac2f74f46a00b72)
- Fixed issues with network timezone downloads crashing on a empty return. [`0209852`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0209852af5c4af2bacfd5759f1bea6325b03e62d)
- Fixed issues with network timezone downloads crashing on a empty return. [`979bf70`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/979bf70f5c1fac506a8c4d8404595f788a2bc4ca)
- Fixed minor issues with provider rss caching code. [`f814de4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f814de4c82fb9778bb89157986aba1aca22ad1c2)
- Fixed more issues with mass editing of shows and episode status editing. [`f302ef3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f302ef3d770a9400ae7b7fd101539136d89e1c84)
- Fixed WebFileBrowser code in WebUI [`9e2c753`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e2c753d4b711b69acc42255e5c37042bf5158ba)
- Fixes for issues relating to multi-threading, webui, and databases [`9466bdd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9466bddc3ee2679fe476b02d94b6227381536637)
- Fixed a bunch of bugs/issues with tvcache module code flow and added in proper error handling for the threaded cache updates plus resolved some provider issues. [`4254916`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4254916ae917c9652e763bf2c92c3eea91bf504b)
- Fixed issue #1055, adding existing shows with prompt for settings [`de24e52`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/de24e52be6cdf456e7dbdd042e154806ec04c586)
- Fix UI notification issues with auth [`c6c0f96`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c6c0f9600b282b79f6cfc2b8ccc1fd5985496874)
- Possible fix for database threading issues related to async calls from webui [`d2b6145`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d2b6145f8cda8418e5f8a95d455f87f36923bfaf)
- Updated IMDB libs. [`2354c74`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2354c742475c69f50403092a549eb44688121c92)
- Fixed sickragetv/sickrage-issues#109 - resolves logging issues related to new code added in via last updates. [`466ced4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/466ced4c02174f7492a24d5d4817d2c95b9a5fd3)
- Fixed small cosmetic bug with trakt trending shows page. [`a14969f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a14969f4bf53e954ce1d01bf44c1abea30b882a2)
- Fixed issues with newznab/torrent provider searches. [`3d7e460`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3d7e460079825dee69a4ebe1db8034f93eac4ead)
- Fixed manual post-processing issues with WebUI. [`78bfc40`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/78bfc4075760dae8ddbab977df558936454e6c98)
- Improved async threading code for WebUI [`46bd600`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/46bd600da01ee33e8035682d83875752e08d39b0)
- Fixed issues serving static image content for banners/posters and misc other static images, improves overall performance of webui as well. [`efc2aad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/efc2aad782514666e938b4a3161477b1333b9d45)
- Possible fix for issues #1016, #993, and #1024 - Unicode decode/encode issues [`86e7912`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/86e7912c412b2b8f6e4678d14d575a8553e09ac0)
- Fixed bootstrap @grid-float-breakpoint [`f2bcc72`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f2bcc7217c391ea823f0e0ed99ababaef4b3622d)
- Fixed issues with network timezone downloads crashing on a empty return. [`3f29439`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3f29439ff36980f7e17623dca30b7f045801d501)
- Fixed sqlite code to work better with multithreaded webui code [`64bdd4d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/64bdd4d64a08216a63ecec3db60c5b6cb5018aa7)
- Fixed issues with cached images not loading correctly, major speed improvement! [`785c2d3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/785c2d37db0e5b27485eac2f7231235049148549)
- Fixed unicode issues with sqlite3 database queries [`d716430`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d7164308a5d3b2635244a701147d3472c2eebae0)
- Fixed issues with network timezone downloads crashing on a empty return. [`0b403a4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0b403a419c35505c68ff130145a3da59c83712a7)
- Fixed issues with adding shows via WebUI [`3a2a5f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3a2a5f9d70565f58f06420e91944a71a6563893c)
- Fixed issues with randomly returned empty show statuses, added tvrage status mapping to ensure it never gets returned incorrectly. [`9000dbd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9000dbd10a42a71979440437303b62bc9d419364)
- Fixed WebUI issue displaying main index home page [`5fa6793`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5fa67936aa381002769e88d24928c976cc6b4d82)
- Fix for issue #1034 - skipping: 'list' object has no attribute 'feed' [`26e82ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/26e82caa844cd91dcc834eacdedbf7be3fbad105)
- Logging class now uses a custom censored formatter to filter out sensitive information from being logged. [`9eefc80`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9eefc8034bc77b9c36b50b42bef20ba7f110cc06)
- Fixed sickrage/sickrage-issues#105 - old code that needed updating that was causing unicode issues. [`f713567`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f713567d60398cf61cf0caa2425cf5199482649c)
- Fixed issue #1092 - auto post-processing scripts re-coded to work with new login system. [`931d5f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/931d5f41c2914f845d9461631f8330bcd81f1219)
- Fixed issue with login url [`ac70dd3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ac70dd38c258ad527ed20e17a7b70356645281af)
- Updated travis-ci tests [`a70aca6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a70aca6f7c6e5b1cc9d0273394212d5a21043e78)
- Fixed issue #1105 [`467c427`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/467c42747f7ff5b78cec0bbedac9e3a45f8cf408)
- Fixed few misc things related to new logging code and webapi [`949c564`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/949c56439cfb56726ed96b7ac1f3d9b3417ae86d)
- Fixed issues with network timezone downloads crashing on a empty return. [`35af9ac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/35af9acadb05dd853689372b88f79b0728785408)
- Possible fix for issue #954 [`35c84c9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/35c84c9449df7d0f1a197a8984850fd1c34eea5a)
- Update readme.md [`0dba924`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0dba924eb55c9006108ca4c66cea7733f19581d9)
- Fixed small cosmetic bug with trakt trending shows page. [`2cd72ad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2cd72ad4e8f5dab9474ca43b54ac1b41d2e19580)
- Fixed issues regarding adding of existing shows. [`d449687`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d44968789f7377f1d5484108e04b1d7d03274508)
- Fixed small cosmetic bug with trakt trending shows page. [`7f0dd9c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f0dd9cbef7af31cfdcd590fe4aa5dfa9fb33383)
- Update contributing.md [`fa230b1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fa230b132c668bd5e4cb8e60619d0f022bc5314d)
- Fixed issue #990 - was not properly calling lower function [`5f1c16c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5f1c16ca02a3e159386cdde33f08dd21edbef50c)
- PEP8 performed on unitests [`76754ff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/76754ff2baf198904cabe210d1ed005433370266)
- Fix 2-row on home [`f4450be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f4450bec46010fa9af09e4c31c473800496d076b)
- Fixed webapi jsonp response code [`71d95b4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/71d95b463e7368c1e4f2671cbf94936e466a93d0)
- fix to work with new login system, check for http status 302 [`77f70ad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/77f70ad0df28d23521ecfa5bf889c72f9bfcebc3)
- Updated travis.yml file [`68cca69`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/68cca69b9fc14ba5dc5d5df8723c997fb5e073ce)
- Fixed few misc things related to new logging code and webapi [`3214f87`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3214f879ac2ddc40754f7e07c2b8dff31cc6648d)
- Fix for reverseNames missing from new logging code [`9dc03c5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9dc03c5d6aad74acd04ff91bbef720ccd0e9210c)
- Fix for issues regarding string 'None' being set in config.ini causing issues, this will reset it back to the default setting to avoid further complications. [`22fd308`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22fd3086aede8844d5519be5415bfa8382eab3a6)
- Fix for issue #1041, dict has no attrib entries error [`df78fd6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/df78fd6669dafa00587df23d56d4a9dc7796ad17)
- Fix for issue #986 - No RID in search params for NewzNab providers [`e212a09`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e212a09520b88bc20a9090bdfda30e369ea4eb6e)
- Fix for issue #928 - Regex updated to take into account possible parentheses surrounding the season/episode numbers in searches [`3d45497`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3d454979dbb9eeca517171fb2a11f2bc8b891e83)
- Fix for issue #1009 - added show and release_group attributes to properFinder module. [`a946f8a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a946f8aca5059af668b006af1e5e52b9f8e1f8bf)
- Fixed backup and restore - issue was present in javascript file with incorrect url [`1ff906f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1ff906f3ff1372faa45c93d2922cdf410d6f15f5)
- Fixed issues with mass editing of shows and episode status editing. [`98a32c5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/98a32c56654d9f25139916ca19f57f1e540979ce)
- Fixed error 'No handlers could be found' issue [`33c070a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/33c070ae13e0cbc3e13a762e757208383ef50025)
- Fix for logs being sent to error log viewer when not errors. [`d1341bf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d1341bf7770ea6cd296a8e7bba1d93adbd54b098)
- chmod +x all_tests.py to avoid permission issues [`fa7d32e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fa7d32e40373950578081d772fe1d3a2d7a8a0a8)
- Fix for unicode issues with image files [`a311b66`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a311b665bab4f32adb00d28910b0a74fd3f2694e)
- Linked post to get for WebUI [`421e807`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/421e807aa6a6725d488a3ee0af76f2a54156871f)
- fixed yet another typo in travis-cl yaml [`96929e0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/96929e09484b63d4f46d62a22ab3275f391a7442)
- Fixed typo in travis-ci yaml file [`ead2f97`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ead2f97f785408a9ab9050fbeb9ca73ac022d7e4)
- Fix for issue #1111 [`269bf23`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/269bf2333b5dcf6deb67ad0274ba76916a0a6ec3)
- Fix for issue #1004 and issue #989 [`e5af1cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e5af1cb4ff0898946d660e5e68291869460331e2)
- Fixed regex issue for naming patterns [`6f5474b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6f5474b999563da8b055f4b67bb0ddec83761866)
- Fix for missing kodi metadata modules [`4bd86b4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4bd86b481e0044891c0c6cd0e4a4d1f985b25549)
- Fix for missing kodi module [`97bb71a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/97bb71a6a5966957219d39cb3cb18401c6876ee0)
- Merge tag 'v3.3.3' into develop [`e02932c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e02932c16a8ef3a8e00e32e8e1f3161416034028)
- Merge tag 'v3.9.2' into develop [`fd03e03`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fd03e0394dcfbbd35edd2b60a4309aefdddf9f1d)
- Merge tag 'v3.2.1' into develop [`b71dc36`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b71dc36801820b7a7107c20372fa55989b42c29d)
#### [v3.9.2](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v3.3.3...v3.9.2)
> 26 November 2014
#### [v3.3.3](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v3.2.1...v3.3.3)
> 27 November 2014
- Added features for web api [`#949`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/949)
- Added Smithsonian Channel and Esquire Network Logos [`#960`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/960)
- Add custom nzb category and torrent label for anime [`#961`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/961)
- Fixed webapi jsonp response code [`71d95b4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/71d95b463e7368c1e4f2671cbf94936e466a93d0)
- Merge tag 'v3.9.2' into develop [`fd03e03`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fd03e0394dcfbbd35edd2b60a4309aefdddf9f1d)
- Merge tag 'v3.2.1' into develop [`b71dc36`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b71dc36801820b7a7107c20372fa55989b42c29d)
#### [v3.2.1](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v3.2.0...v3.2.1)
> 25 November 2014
- Merge tag 'v3.2.0' into develop [`0c06c3a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0c06c3a82e6d5995c9b3993aa7f58fff4dcc626f)
#### [v3.2.0](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v3.1.0...v3.2.0)
> 24 November 2014
- Fixed up FreeBSD init file to use rc.subr [`#936`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/936)
- Strip year from show title when adding existing shows, so show is found ... [`#937`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/937)
- Fix for issue #939 - utf8 decoding issues [`f73aee7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f73aee78ccce568989d519454497028f105fc36b)
- Update readme.md [`97d44f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/97d44f9e01f6251eb80ce89173e03709dac44f82)
- Fixed pnotify issue [`4369802`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4369802ddea49e1130fabc6460fa9fbf20770f6c)
- Fix for issue #942 - Previous code update borked webapi code for show's cmd [`1cd91e6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1cd91e6cc52de6fdf04a884c4c8137202a550ae7)
- Fixed issue with default_ep_status when loading from DB. [`6f83328`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6f833286b7f45833959796b704cd69dfc0a63bcb)
- Fixed startup issue for python 2.6 end-users, had to make some compatibility changes to the ftfy libs [`b67c186`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b67c186ed897e6d6e8abf8fcc0021bb0c7717d64)
- Fixed backlog webapi issue [`47ef5bf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/47ef5bf2b2b225c1a276e173a4342d998b8bfdf3)
- Removed obsolete tvrname reference from tv_tests [`ec62084`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ec6208428e7b552b3b87b9c90e7d004b8f0b7e52)
- Merge tag 'v3.1.0' into develop [`81128f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/81128f6cf2b7fd2da11b47a9d60c01bc3d86c0aa)
#### [v3.1.0](https://git.sickrage.ca/SiCKRAGE/sickrage/compare/v3.0.0...v3.1.0)
> 22 November 2014
- Add provider name to notifiers [`#909`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/909)
- [New GUI] Prevent Airdate column to wrap [`#931`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/931)
- Add location, filesize, subtitles and releasename [`#932`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/932)
- Fix invalid continuation byte for webapi [`#934`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/934)
- [Provider Options tab] Only configure providers that are enabled [`#924`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/924)
- Instead of checking for NULL when trying to update trakt.tv library or watchlists we now check length [`8320672`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/83206726699b4a3cf94687fb73b5eede3abf4886)
- Fix for issue #933, resolves github comparison errors during update checks [`e0f7860`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0f78603cb89ef2ab67fd1fafdb421a063d79048)
- Fixed missing system path appends that where causing issues for travis-cl testing [`26ae17d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/26ae17d34996897a34ff1186cde6020ea0b0722a)
- Fix for issue #933, resolves Commit object attribute issues [`de23635`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/de23635e286e3b8a2c287f0597699cca784a2b99)
- Fixed issue with scene exception tests [`ed4c99b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ed4c99b6f08baed55454c83823693c0b26c6bb08)
- Fix for anime processing issues [`04a83ac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/04a83ac3fb79dce1bc657f869e6de6562a046c51)
#### v3.0.0
> 20 November 2014
- Respect cache. [`#917`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/917)
- UI improvement on Add Show pages [`#907`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/907)
- Fix missing HTML in notifications resulting in incorrect formatting. [`#1`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/1)
- Update PNotify lib. Make notify close button always visible. Fix issue w... [`#149`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/149)
- Fix missing header and text in poster layout when network is none on com... [`#148`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/148)
- Fix parsing utf8 data from tvdb and tvrage [`#123`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/123)
- Fix growl registration not sending sickrage update notification registration [`#122`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/122)
- Fixes unicode issues during searches on newznab providers when rid mapping occurs. [`#95`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/95)
- Make all init scripts executable by default [`#106`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/106)
- Tweak CHANGES.md. [`#108`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/108)
- Fix Coming Episodes/Layout Calender/View Paused and tweak its UI text. [`#107`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/107)
- Fixes changing root dirs on the mass edit page [`#98`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/98)
- Change API now uses Timezone setting at General Config/Interface/User Interface/ at relevant endpoints [`#82`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/82)
- Change to separate stable and develop only items in CHANGES.md. [`#66`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/66)
- Fix the home page from failing to load due to data_date not being set. [`#65`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/65)
- Combined 'Delete' and 'Remove' buttons in to one on the individual show ... [`#56`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/56)
- Fix theme identification for spinner when restarting. [`#45`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/45)
- Implement automatic saving of poster layout sorting options on show list [`#40`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/40)
- Update Calender View on Coming Episodes Page. [`#8`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/8)
- Various tweaks to UI including additional use of fuzzy dates. [`#875`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/875)
- Tiny bugfix in searchShowSubtitles [`#868`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/868)
- Subscenter support [`#867`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/867)
- Fix for failed episodes not counted in total [`#863`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/863)
- Network logos for Australian ABC, ABC2, ABC3 and Sky Arts [`#859`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/859)
- Switchable themes [`#858`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/858)
- Add theme_name to config and expose THEME_NAME global [`#856`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/856)
- Changing /calendar to add Season and Episode to the description [`#852`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/852)
- Revert "fix typo on network logo" [`#851`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/851)
- Added a "flip" search order option to new GUI [`#850`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/850)
- Add global required words [`#849`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/849)
- Adjust transmission timeout for slower systems [`#848`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/848)
- Fix git checkout when notifiers are enabled [`#847`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/847)
- Catch airs/network set to None [`#840`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/840)
- add postprocess to api [`#837`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/837)
- Custom naming for anime [`#834`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/834)
- fix transmission seed time [`#832`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/832)
- fixes to make trakt watch list work [`#826`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/826)
- Threads dailysearcher process for each provider. Allows dailysearcher to... [`#824`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/824)
- Revert "Fix for updating queue icon when DailySearchQueueItem is running... [`#823`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/823)
- Dev [`#822`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/822)
- Fixes daily search and speed improvements [`#820`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/820)
- Updates to Pushbullet functionality to address rejected keys / connections, provide "All Devices" functionality [`#812`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/812)
- Update kat.py [`#819`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/819)
- Update comingEpisodes.tmpl to prevent a 'NotFound' error for... [`#811`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/811)
- Fix some of the unit tests [`#805`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/805)
- Add first revision of calendar to coming episodes [`#804`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/804)
- Fix RssTorrent where there may be empty values in configuration [`#803`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/803)
- Update .travis.yml, fix imports and tests [`#795`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/795)
- Dev [`#794`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/794)
- Leading zero fix for Anime. [`#790`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/790)
- Fixes backlog for newznab providers [`#789`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/789)
- Fix proper search for t411 [`#787`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/787)
- Add search queue info to ManageSearches page [`#786`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/786)
- Fix default post processing with sync files option [`#785`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/785)
- Added an option in Post Processing options do activated/deactivate postp... [`#784`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/784)
- Dev [`#781`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/781)
- Added the torrent provider for www.t411.me tracker [`#780`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/780)
- Do not log ERROR when show isn't in list. Log WARNING instead. [`#762`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/762)
- Fix #3 for daily/backlog checkbox saving [`#779`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/779)
- Fix infinite loop with dognzb [`#778`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/778)
- Test #2 to fix daily/backlog checkboxes with custom newznab server [`#775`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/775)
- Fix for daily/backlog checkbox values not saving correctly on providers [`#774`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/774)
- Testing fix for missing api key on newznab providers [`#773`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/773)
- Fixed missing slash on Kat mirror URL [`#765`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/765)
- Add transmission seed for X hours option [`#764`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/764)
- Update adba libs [`#763`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/763)
- Fix missing fid listing on NotifygetMessageResponse [`#761`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/761)
- Replace tabs with spaces in adba libs / PEP8 [`#760`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/760)
- Dev [`#759`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/759)
- Update bitsoup.py - new table format [`#758`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/758)
- notifiers/libnotify: fix syntax error from #624 [`#756`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/756)
- Added indexerid to CMD_Show(ApiCall) [`#755`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/755)
- Fix for torrentbytes provider where torrentid is <6 characters long [`#752`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/752)
- Fixes rejection of invalid torrent files [`#754`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/754)
- Change minimum backlog frequency to a more acceptable value [`#751`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/751)
- Fix ABD shows manual and backlog searches [`#749`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/749)
- Fix sorting on mass update page [`#746`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/746)
- Fixed result content for Season Pack results [`#743`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/743)
- Dev [`#747`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/747)
- Fix for utorrent label setting [`#745`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/745)
- Should fix some utorrent, rtorrent and deluge [`#744`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/744)
- Fixes anime exceptions being cleared when editing the exceptions on edit... [`#741`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/741)
- Update trakt.py [`#740`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/740)
- Support for newznab offset parameter - https://newznab.readthedocs.org/e... [`#736`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/736)
- Set blank variable [`#738`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/738)
- Fix for torrent rss feeds not validating on add [`#737`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/737)
- Use correct item name [`#735`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/735)
- Fix series remove and add all episodes remove [`#734`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/734)
- Dev [`#732`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/732)
- Fixes speedcd provider issues [`#731`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/731)
- Dev [`#730`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/730)
- Third fix for zip updating and checkouts [`#729`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/729)
- Scene exception list not updated, Double show names in scene excep list after manual scan [`#728`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/728)
- fix for multi ep format setting load [`#727`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/727)
- Second attempt to fix zip updating [`#726`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/726)
- Dev [`#724`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/724)
- Update bitsoup.py [`#722`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/722)
- Possible fix for updating when using zips from github [`#721`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/721)
- Dev [`#720`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/720)
- Fix for omgwtfnzb skipping: release error [`#719`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/719)
- Dev [`#718`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/718)
- Fixes issue with search page from PR 713 [`#717`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/717)
- Dev [`#716`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/716)
- Fixes even more daily search issues [`#715`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/715)
- Consolidate more provider code [`#714`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/714)
- Add priority option for daily snatches (inc force) [`#713`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/713)
- Return to linux line feeds [`#712`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/712)
- Fix non-anime propers being skipped for not having a version [`#710`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/710)
- Fixes listing branches for when using source code [`#709`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/709)
- Fixes for trakt settings not saving [`#708`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/708)
- Halt post processing if lftp temporary files are detected [`#707`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/707)
- Fixes resetting of auto postprocessing timer config [`#706`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/706)
- Fixed search pattern for checking ignored and required words in release names [`#703`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/703)
- Fix for HDbits tvcache issue [`#704`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/704)
- Fix for tpb ABD shows [`#705`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/705)
- Sync master<->dev [`#700`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/700)
- Sync master<->dev [`#699`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/699)
- Update tvrage_api.py [`#698`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/698)
- Trakt method, error checking, remove series [`#697`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/697)
- Added Danish Public Service channels [`#696`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/696)
- Fixed unbound method editShow() error [`#695`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/695)
- Fixes update issues for source code downloaded versions [`#694`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/694)
- Merge pull requests and changes from DEV branch into MASTER [`#693`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/693)
- Changes "no_season" regex to support XofX naming [`#691`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/691)
- Halt postprocessing if temporary btsync files are detected [`#690`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/690)
- Tidying provider code [`#689`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/689)
- HDbits fix [`#688`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/688)
- Fix <a> element so that it doesn't leak to other elements [`#684`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/684)
- Remove unnecessary code from nyaatorrents provider and PEP8 [`#679`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/679)
- Animezb tidy proper code and PEP8 [`#680`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/680)
- Tidy fanzub proper code and PEP8 [`#681`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/681)
- Fixing anime propers due to missed code when rebasing [`#682`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/682)
- Handle case where we don't get back valid data from trakt [`#683`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/683)
- Add network logo [`#669`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/669)
- Completed migration to v2 Pushbullet API. Added extra debug logging. [`#671`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/671)
- Anime proper support [`#667`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/667)
- Remove old Code that caused an exception in the iCal Feed [`#660`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/660)
- fix episode filtering [`#665`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/665)
- Fixed: pushbullet notifications don't work [`#666`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/666)
- Fix for incorrect show snatches [`#662`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/662)
- Tidy PP log message [`#653`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/653)
- Fix proper searches with ABD and sports [`#652`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/652)
- Added Support for new append method of NZBGet 13+ [`#649`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/649)
- Fix for symlinking during Post-Processing [`#650`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/650)
- Updating provider clear cache log message [`#647`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/647)
- Add Bitsoup and FreshOnTV(TVTorrents.ro) providers [`#648`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/648)
- Add animezb provider [`#638`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/638)
- Add TorrentBytes provider [`#637`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/637)
- Fixes web-dl quality detection for some episode naming patterns [`#632`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/632)
- Minor GUI and console fixes [`#626`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/626)
- Adds custom RSS provider ratio setting. [`#623`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/623)
- Allow the detection of subtitles embedded in mp4 files [`#627`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/627)
- fixed broken images when changing web_root from default (empty) [`#630`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/630)
- Fix for 'add to my list' option defaulting to on upon a restart. [`#631`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/631)
- Fixes downloads column sorting order for shows with all episodes ignored [`#633`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/633)
- Adds network logos for bs11 and niconico [`#634`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/634)
- Fixes blank release group field for animes on history page [`#629`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/629)
- Relocating group labels and required words on show page [`#628`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/628)
- Add support for animes with a different series name per tvdb season [`#625`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/625)
- Notify users on SickRage update via notifiers [`#624`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/624)
- Fix next backlog date [`#621`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/621)
- Fixrsscookies [`#622`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/622)
- Port:Add safe replace existing file is larger but new file is proper. [`#613`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/613)
- Port fix change setting episode status [`#611`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/611)
- Port:Fix omgwtfnzbs findPropers. [`#610`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/610)
- Refactor scheduler and upstream ports. [`#609`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/609)
- Option to NOT rename .nfo to .nfo-orig [`#608`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/608)
- Add moderator to confirmed TPB torrent posters [`#607`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/607)
- Fix for 1080p HDTV anime [`#596`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/596)
- Destination option for the Synology DS [`#593`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/593)
- Fixed setting ratio in Transmission [`#599`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/599)
- Add UI option for users to enter their own Pushover API key [`#604`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/604)
- Update anime-list.xml and animetitles.xml [`#606`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/606)
- Network logo changes [`#594`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/594)
- Renaming network logos files to lowercase as SR requires lowercase [`#601`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/601)
- Fixes searching with usenet-crawler [`#597`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/597)
- Added cookie support to custom torrent provider [`#582`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/582)
- Small fuzzy moments update: Use day numbers instead of lang dependant names [`#590`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/590)
- Fixing "Release" spelling [`#591`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/591)
- Fuzzy Moments Update [`#588`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/588)
- Update webserve.py [`#576`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/576)
- Fixed missing parameter skip_removed_files [`#575`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/575)
- Update pushbullet.py to include episode name [`#574`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/574)
- Add new feature, check propers interval. [`#567`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/567)
- Don't add portnumber when restarting with reverse proxy enabled [`#558`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/558)
- Update boxcar2.py: Title and sound [`#563`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/563)
- Add new feature, set file date to episode aired date. [`#565`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/565)
- PickBestResult x264 over xvid where both exist and quality is equal [`#566`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/566)
- Update boxcar2.py [`#557`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/557)
- Fixes Invalid ratio error when ratio is not set for transmission [`#549`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/549)
- Add forgotten 'self' argument to _isSection() [`#559`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/559)
- Fix Renaming issue for not PROPER release generating two dot in filename [`#555`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/555)
- Remove Nl sub Filter [`#554`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/554)
- Fixes Deluge settings appearing in other clients [`#552`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/552)
- fix typo in xbmc notifier [`#551`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/551)
- Debian style LSB init script [`#522`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/522)
- Deluge bugs: Labels were always lowercase, and SSL certs were always checked. Doesnt work with selfsigned certs [`#519`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/519)
- Adds Per Provider Seed Ratio [`#507`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/507)
- Fixing issue #463 [`#506`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/506)
- Datetime fix2, fixes #381 [`#505`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/505)
- Workaround for #336 [`#487`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/487)
- Update search_queue.py [`#484`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/484)
- backport: xbmc always on option - fix #315 [`#471`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/471)
- Add Boxcar2 Notifications [`#450`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/450)
- Fix downloading from foreign section of SceneAccess [`#464`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/464)
- Fix for #390 [`#429`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/429)
- A fix for #389 [`#409`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/409)
- Remove old obsolete code, that could course an error [`#399`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/399)
- Add proper handling for reverse proxies [`#360`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/360)
- Update the Plex notifier [`#324`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/324)
- Fix typo in db.py [`#341`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/341)
- Pushbullet Changes [`#299`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/299)
- Create an INDEXER_DEFAULT config variable and fix traktWatchListChecker.py [`#106`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/106)
- Fixed 'NoneType' object has no attribute 'status' error [`#267`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/267)
- Fix API history request in dev [`#262`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/262)
- Bugfix for logic error in sql queue for ical (paused shows) [`#247`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/247)
- added gentoo linux init script [`#260`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/260)
- Fix archive search and correct logging for foreign searches [`#216`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/216)
- Fix for API using indexerid instead of tvdbid [`#159`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/159)
- Adds seed time and seed ratio to utorrent client [`#162`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/162)
- ical Bugfix and Change from All-Day Event to Time Event [`#172`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/172)
- Made space for config menu in top bar of gui on small screens [`#85`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/85)
- Fixed issue #49 [`#69`](https://git.sickrage.ca/SiCKRAGE/sickrage/pull/69)
- Respect cache. [`#903`](https://github.com/SiCKRAGETV/SickRage/issues/903)
- Fix #6 for github module not found issue [`#6`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/6)
- Fix #5 for github module not found issue [`#5`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/5)
- Fix #4 for github module not found issue [`#4`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/4)
- Fix #3 for github module not found issue [`#3`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/3)
- Fix #2 for github module not found issue [`#2`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/2)
- Merge pull request #779 from adam111316/checkbox_fix [`#3`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/3)
- Fix #3 for daily/backlog checkbox saving [`#3`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/3)
- db locking issues fix #2 [`#2`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/2)
- Merge pull request #505 from Prinz23/datetime_fix2 [`#381`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/381)
- Merge pull request #471 from pmaciocia/xbmc_always_on_315 [`#315`](https://git.sickrage.ca/SiCKRAGE/sickrage/issues/315)
- Fixed issues with editing/saving custom scene exceptions. [`d02c0bd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d02c0bd6ebcf1cbfe43708b1093aace586f28481)
- Further improved memory handling of bs4 for torrent providers. [`403c267`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/403c2679538cc724a0107551168ee826010d4ed6)
- Replaced cherrypy with tornado which helped resolve our memory leak issue. [`d73cc1c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d73cc1cbbd22c706d5fc77862dedafc1c0b04133)
- Reverted new regex changes, not compatible with enough platforms to warrent keeping. [`893574b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/893574b2edd855e6387d76efe956bd834f75bbbd)
- Upgraded CherryPy libs to 3.3.0 [`cec4ed5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cec4ed573d5edcdfd27853f97bea1510b7a526a1)
- Fix for missing github modules, forgot to add folder to git repo [`d96597b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d96597bf2798daea949cc495d7ba2d04f1b97c4c)
- Improve UI to display fluidly on different screen sizes. [`2c510aa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2c510aa21040437707c3c7ab063386c28a7cf91e)
- New skin [`8847fa0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8847fa056d0880ccabc8be16fa78128362019451)
- Playing videos from display show page has now been made opt-in, you can enable/disable via general config menu. [`4246744`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/424674464f50e09afa2848abdcad18aa9ebdb108)
- Update imdbpy libs to v5.0 [`2dcd26e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2dcd26e69c94daa4b23cdc8497c1876f5d799a27)
- Updated tornado to latest stable code, fixes issues with auto-reload [`327df66`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/327df6682e516317c9affce4254ddd6975872fdb)
- Code Clean up and regex fix for "no repeats" error (reverted from commit 8ecd5a196db7c4ef235a87c6110e91596bf5ca34) [`10637f8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/10637f8f2948a5aa3dfab119b7b6111db86340e4)
- Updated unrar2 lib [`5b23d83`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5b23d8370476126fe82520449f744e93e1472b11)
- Fix for unrar2 [`b547226`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b5472263533c59f3e917407da316bf81b228370c)
- Fix for manual and backlog download/search issues. [`1398c38`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1398c38275f25f168c9961edb439f808bdabd44c)
- Removed snatch queues to reduce memory footprint. [`aafe9ad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aafe9ad522504b8a92b6235f552396e176855b53)
- Fixes season pack and episode only searches [`816a3d9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/816a3d95720c0cc9d932dbe121ce615cdc2daa7a)
- Removed a extra space that may have caused issues in future [`12b8fc9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/12b8fc9990705968c07f288fa1d771f67e8da5c0)
- Re-wrote daily searcher to search for unaired and wanted episodes going back as far as 1 week, also moved it so it queue's its items now. [`c65573a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c65573a8d73d9fe8caf06e059bc6f1bb1c05d087)
- Fix for failed download issues. [`b931044`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9310444e5b5f08e4d62347130433b8b4d4b64c0)
- Improved find propers code. [`f01c585`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f01c5852d4f1241b062233ed4f4a7bd7afc7f9b6)
- Complete re-write of backlog search. [`a39c881`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a39c881cb3d4dc1a23df2d0202330311ba729831)
- Fixed app performance issues from recent upgrades. [`c5f933e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c5f933e4c8f724bf98224a38beae8b4aa1fb41f9)
- Fixed issues with post-processing. [`f7b11e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f7b11e1e98599bfd44fc91700c93a471545aa784)
- Fixed dupe issues with backlog searches. [`c350c0f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c350c0fdf94bde366484aa7d7c0b14ecabb4017c)
- Fix for air-by-date and sports shows when searching for full seasons. [`415e0df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/415e0df536f1c449d069aa91e8ba0450dc44acdd)
- rss cache updates and daily search have been joined into one function. [`55f27c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/55f27c4f400934c68147e7ea96c8fe4b16c389b8)
- Fixed find propers. [`854de69`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/854de696835076d659ad6b6f5e3b494c7c34a198)
- Fixed issues with scene numbering being overwritten by ep objects. [`70e7f1b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/70e7f1bfce3400ed94a4a806b5024490cde577d0)
- Fixed issues with per-provider torrent ratio settings, now can be left blank to default to client ratio setting. [`b499e4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b499e4b6db20d88b38b11bc548bde376d1ad074c)
- Fix for torrent ratio's, switched them from being stored as strings to integers. [`7673cd5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7673cd5cc9d8e797a5b83cf956ede4eaae3deb7e)
- Fix for scene name repeat bug when displaying show. [`de01fa1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/de01fa1e37f873d308a1c33a3789ccf4fd4ff292)
- Fixed issues with queues. [`ab8d9e6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ab8d9e64050c0bfcf9d2fbaa5999d58ef157b797)
- Fixed metadata code to add proper indexer info to the tvshow.nfo files [`bde70f1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bde70f188169e35ad5a7d592a6a4a262e4a6f4c5)
- Fixes issues with possible duplicate downloads. [`93573ab`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/93573abdc4170a3241055212f885d0b72810f379)
- Fixes issues with daily searcher not snatching its results when it has any to snatch. [`66e499a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/66e499ab23e6e06dc8ee4fd91afd99d1c2ddfe70)
- Converted NZB providers to new dynamic config style format. [`5f328eb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5f328eba5f2e04395e2eb813943584ad0676ab18)
- Fixed provider ratio issues, not can be set via .1 increments [`fab8329`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fab8329e2363882535a1686f5b150646b7c8d356)
- Improved manual, failed, and backlog searching. [`734de67`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/734de67684f494442e7f4eabf89fb81cf29d09ed)
- Fixes errors caused by duplicate newznab providers [`d6a9426`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d6a942698aed46aed6a66a63a5b0af0bd123ce03)
- Fix for date/time display issues. [`f4b71b7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f4b71b720379efd63c234328e2ee8f4c884cc303)
- Fix for air-by-date downloads. [`f8035e8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f8035e800e92fb66a63b09cd6330c938c0148c56)
- Fixed cache issues. [`dd16da1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dd16da1a5fc65a3efe8efd9eddad2f0371967623)
- Fixed issues with search results not being snatched when searching shows with custom quality settings. [`8ac8150`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8ac8150eb39d2e4b16604d0c1298946b31b094ce)
- Fix for issue causing issues loading and saving search providers [`a350be3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a350be339c6e035ff082fb505b1ff974a03de8d9)
- Code cleanup [`41366dc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/41366dcba76e1cee2a3a76441ea7126cdcd0f361)
- Fixed potential backlog issues. [`a6d30ac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a6d30ac4258fcf051066e962fa4da2847df45789)
- Fix for restart and PID issues. [`42b6211`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/42b621103f5a77abc1fe5823d40a376977f7bc5a)
- Fix for Next Ep airdates. [`9cd9576`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9cd95762328d5125dc346fb4d1bdfdb966b10304)
- Fixed internal indexer scene name cache which resolved issues with searching and snatching. [`4da248e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4da248ef9b0c7a4ccc72fb9fb65d7f02575c7e46)
- Fixed issues in mede8er metadata module [`f8a8f4c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f8a8f4c5b4b14447076ceeb4ef0d37c9d93bf0a6)
- Removed some sleep timers to improve overall speed of sickrage. [`fa11b4e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fa11b4ef3ab20ec56d3b49ffbfbff2dee20cccda)
- Fix for failed downloads and improper storing of release name in db [`f78ed64`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f78ed64878761640be4fef8c3e564cd827cc41ea)
- Fxi for failed downloads [`a12085c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a12085cbfc7bfc49e17fd47cacbe7e6a30ef76d8)
- More namechanges [`177dbc0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/177dbc0f222d12371da35f93c86f5fab8edbc232)
- Fixes issues with skip removed files option. [`a4c790e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4c790eedc59e03943112cc6303deaa9482888ee)
- Fix for when no best match is found. [`5f80375`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5f8037530a5738af3c9bef3f8a6256de8cb5343a)
- Changing names, branches, URLs [`3163bad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3163badb4cd5247851bb71dad1bcf7958ef8d6a7)
- Fix for manual and backlog searches to insure maximum results are returned [`b8a499b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8a499b3d3ceaef16d0dac914a33e7ad03d13a03)
- Revert "Fix for findpropers and newznab providers" [`95adb13`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/95adb131e13d8e60fbf1f30a7304d8daeec529de)
- Fix for findpropers and newznab providers [`cfa5d99`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cfa5d99066958701274c36daaf72acad1513cd47)
- Fix to insure pre-release downloads/snatches don't get reset back to unaired. [`3517952`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/35179525363b2bd2bef628f6fca8d57c595cdc9a)
- Fixed a couple of bugs related to deluge [`d0105a2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d0105a2f6a5d8b95de4d3d33bb6e435602886751)
- Improved caching results code, helps with daily searches. [`1fcfa4c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1fcfa4c70a86bfd51b123017bdfb5591c4bc3fdb)
- Fix for possible infinitie loop in searches [`905d2b4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/905d2b4eafe7c16d396e54e04ea7a2e3781476aa)
- Fix for backlog and manual searches not being executed [`7c9e4b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7c9e4b24d51929f021affcefaaa4ccdec3d938fc)
- Fix for XBMC notifier when XBMC has no shows in library. [`bea999b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bea999b6399aa20db2494ee0f6bb632186539c99)
- Removed global seed ratio's [`83d7e9f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/83d7e9fb694d66413fe14b5253953166252eab42)
- Fix for thread name [`e3bf972`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e3bf97285c14762691615090e7e68cc7059e54a9)
- Fix for #315, backport xbmc always on option [`77e9988`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/77e9988980fbc3249f9b61726d3ff0a6829a8d54)
- Fixed more unrequired search strings from being created and wasting our time doing duplicate searches [`e309aa2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e309aa2cbfce4540ee16f6c2f45d14723d267cb0)
- Fix for failed downloads [`c761f32`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c761f32c85e6cae14454c900700b91e09f95cd68)
- Fix for adding new and existing shows not showing up in show list [`f742f8a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f742f8a51a31c1e174dfce40b5c78a27392e701d)
- Fixed issue with scene exception updating for custom names. [`78c4211`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/78c42119253cf8239d2b7e553bce888c5fd00e29)
- Fixes issues with provider settings being loaded and unicode data when it should of been stripped off. [`22ec1a4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22ec1a441872f9d46edbd8b3054f514432e5b1f9)
- Fix for sports air-by-date shows [`d2b4ad5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d2b4ad526d6a7aa10f0d3f262f6429be35157afe)
- Fixed for failed downloads issue list index out of range [`98e1d67`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/98e1d67cf9dd7720887527d4d872559f5ccf5285)
- Fixed post-processing issues with shows being rejected and saying they didn't exist when infact they did. [`05cca0d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/05cca0dfe02e6415e1349ba4b30a44be1f630ea0)
- Fix for complete season snatches. [`448a45c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/448a45cf4076218f8744cbf095b22e4a7d2d0df8)
- Fix for managing searches [`f7ded2a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f7ded2a4ed1bbad6330a6fa2dbd88170fd2b3515)
- Moved changes to dev [`06f5f3a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/06f5f3a9aee6d58bc6a020c4debfeae65cd22946)
- Fixed issues with scene converting [`277d630`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/277d630a6fc0892f1e8ee4450cdb49dd69afef13)
- Removed some re-dundant code from daily search. [`a15db17`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a15db1719d48f031cbfc293f499e3c3e092bddde)
- auto update test #1 [`52fca3e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/52fca3e29abbc37d138581ade9a0a3fd1d65b682)
- Fix for manual anime searches [`2c37523`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2c37523ab7a88d719fba0a4c0ad4b7630f0f401e)
- Fix for scene numbering manually when show has incomplete xem mapping. [`2318e43`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2318e43e899c0f5b26ae6359e35a55b67f54a87e)
- Reset on every call of Datetime print function the format to default [`f137144`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f137144bc787058b9d096935df2913bb372374dd)
- Fix for new show searches, now checks alias names as well as series names to get results. [`7a56afe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7a56afe512f001509ca9d61f0ccedb230980dee7)
- Fix for writing new NFO files for updating Indexer info, prevents constant writing on refreshes of shows [`51ff041`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/51ff0413892d7b1841668128d8edb59776098419)
- Fix for issue #546 [`1d01d2b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1d01d2bc52f22edf2f17af5714882e97a93efdc1)
- Complete Backlog searches can now be forced from manage search menu. [`1aff31e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1aff31eaec29c2c4d7f2551d526d2c3edd2d5476)
- Code cleanup [`6558b8a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6558b8ac7192b2ba14d73a6ebab7d0a0a3a04bcf)
- Fixes Invalid ratio error when ratio is not set [`e42cdb5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e42cdb5b4a5a92726e6b5ead1b8374390e564865)
- Fixed issue #472 [`466eba7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/466eba7fa08a10510fe9bcf301c48fc43d755015)
- Fixed issues with post-processing including the web 500 error. [`fc58a44`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fc58a44ba23ef03eb740b247212fdc09b388d1d0)
- More logo changes [`b31b054`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b31b054e0c759fc14db2f29e53deefcbd47d2789)
- Fixed issues for unicode problems for encrypted passwords. [`be001c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/be001c47aefb4750363441c52739dbac77549394)
- Fixes issues when using system default for Date format, it will now properly display it in your locale. [`9a23bfd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9a23bfd0f58d6e444011732b577ecba1d73d33fd)
- Fix for failed downloads [`72278cf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/72278cfcb26f89f80c3fcbc5b7c011e535108991)
- Better detection when to show the button [`514d477`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/514d477a326bf317fbaa4ee74f37d23f238035c9)
- Fix for restart issues [`4a4eec0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4a4eec0a9e1ad81aa01238cca36c7a994773866d)
- Change process title for more clarity when running multiple python progs [`764cf6e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/764cf6e62e6054f81e7b0b30294d8f6a82ed3efa)
- Fixes issue with daily searcher constantly showing it's in progress when in fact it is not from manage searches page. [`347f595`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/347f595dfe4c52799f3e6bc02232ba5abcbfaa2a)
- Fix for restarting issues and slow loading of shows [`4164f00`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4164f00fc8541e2d7f5d88aa46c45d875ed2f88a)
- Fix for issues with fallback search option. [`0b9b622`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0b9b6228ae162c1d54ffa1fbf7399868b5ae533c)
- Fix for alterate scene names [`cded5db`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cded5db5a2f0f28e2cde47c5ffdf23ab37db512f)
- Fixes issue with version update not appearing at top of page [`f5cb9ab`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f5cb9ab84d7dec650d8bd59d56836d0e3bc066ca)
- Fix for migration issues [`7d6e73f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7d6e73f0268e9ab9bce32a4fae6c2ddc5bdd9ef5)
- Fixed for Backlog startup feature. [`a77d8c1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a77d8c1fcbb2c85326e19910ce68a287f6b6de0a)
- Fix for backlog overview errors [`e05344d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e05344d571758609cb271fe79914b2e346e46721)
- PEP8 cleanups [`7bf1246`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7bf12460bef6cf6964d0fca19c9d57696a6fc57f)
- Fix for find propers and newznab providers [`7e711c0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7e711c0665a230da1bb28a2eec6aaaa41e98951a)
- Changed IRC channel details [`dad2c16`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dad2c1623c255a458fd041354ca4c77f8674a881)
- Removed internal cache update checks, cache updates will now perform at the interval setting time you set for daily searches. [`e09c497`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e09c4976a55f217621805e6825a92070a3fbfd7d)
- HDBits fixed! DOn't question just say ... thankyou ;) [`3918917`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3918917f7a33af399289840660bdf516f7d45f96)
- Fix for failed releases not properly converting scene numbered to indexer numbering plus small typo fix. [`5154099`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/51540993be74e42ec72d31bf9bb7b70249771bbd)
- Fixed a issue that was causing multiple search strings to be created for the same season or episode during a search, this would of caused unrequired searches to be performed. [`4576ade`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4576ade4ce37c3d984ec6a3051bbcf1551ad2ff1)
- Fixes date timezone issues [`b0f1f2c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0f1f2c91e28706f1983a661c44979882eeae8be)
- Fixes issue with daily searcher setting episodes past todays date to wanted. [`1f55b11`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f55b11b7d53ea43408f566fa816dc63dca0b50b)
- Fixed issues with daily searcher [`6709ebd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6709ebdf129aed59a00c2879c5dea9e92f69d2f3)
- Fix for search iteration issue [`eeb632f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eeb632fd0fd3363ed5854a800d4e06e11d0a2ece)
- Fix for transmission torrent client and ratio's [`43219e3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/43219e34e33751af0b33cbf8889b4507bd55b473)
- Update pushbullet.py [`f667e8a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f667e8a17ff2819be01fb31a27a5ac74452135c0)
- Fixed air-by-date issues with downloading a show that results in downloading the incorrect show afterwards. [`ed8de59`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ed8de59e91b5516b2ce85b2c016d0a090045ec90)
- Fix to have thread name include type of search [`dc56e77`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dc56e774b682f8c91012582b3095bb77148e5ec2)
- Fix for adding new shows and issue with indexer_timeout [`e3da060`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e3da06000038608154b9a5b93e2c398b5f6500e3)
- Fixes issues with settings and newznab providers. [`2a5598b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2a5598ba0fc367f80e5c82cae7ace6454fe66165)
- Fixed bug that was causing issues with saving config. [`04213be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/04213bebf2a6d94d0874a51b8804ca2c28f93150)
- Output success if *all* the many post processing actions are successful, otherwise indicate a problem occurred if one fails. [`d04937c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d04937cb8bd09a2ca31ed29a5353eabfdd02dba6)
- Naming pattern issues resolved. [`ac7198a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ac7198a852894130f655e3a4a56f8d09ed9975bb)
- Fix for scene exception and scene numbering updates when editing a show. [`9b78e3d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9b78e3dc5e4f54c12b37f58c784da157168a690b)
- Fix for new show searches [`00f38a7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/00f38a7157f95babeb40224d95fae69c777c6e04)
- Fixed missing ui notification for snatched episodes. [`5c43787`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5c4378756053a474e20c06ca237a69cd64a35738)
- Fixed small typo causing scene numbering to indexer numbering issues [`c6b064d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c6b064de23e4b50c5bf3242f0d99ecb9033d040e)
- Fixed timezones (reversed) [`b842185`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b842185bad73b769e84d6f45fd5a07c3a6911add)
- Corrected a sqlite syntax error [`0830de8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0830de89cd4eaf1c14e4e1dd38c0977157dca6ac)
- Fixes missing uid and hash vars [`67073d0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/67073d007ed077561f5dc0a8b27580e6969ee45f)
- Revert "Minor change to subtitle code" [`93471b1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/93471b15e647adf24a6dbf5c0757709741e3d654)
- Minor change to subtitle code [`70c5a02`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/70c5a025807c537bd20ae2c09e64b4d2dc141dd9)
- Fix for looping issue during backlog searches [`1d339b9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1d339b97f6bb0a295951103f8430e1c467795993)
- Fix for imdbinfo key error year [`15815c4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/15815c41ab3d9c6ba8769ba035fabdbe683746a3)
- Fix for post-processing and adding anime shows to your anidb mylist [`6ca979d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6ca979d51bf1b4440334376cda098cc56411b792)
- Update config_search.tmpl [`2d64af4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2d64af4b93d898ce50bee07315d66d22f66ce48d)
- Update config_providers.tmpl [`5b9471b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5b9471b2cdecc6179adc2736148735dcd687c7d7)
- Fix for startup issues after last commit [`03c3c96`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/03c3c9666be4341eba391478931e8c2c84308332)
- Update readme.md [`91abf8d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/91abf8ddceb8dd2841805ff702e33efaa74d9388)
- Update readme.md [`16c829b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/16c829b12e561c9efa29b7d6eac0c3a1e93d5b9d)
- Fixed backlog searches [`85019f0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/85019f07e4694d9d939113982b83edbe702985a7)
- Fixed post-processing issues for anime shows. [`72b4155`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/72b4155b0b66f9e0879ba70070d0372a05899a65)
- Fix typo [`cea8fd3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cea8fd3216146409de52e6e4c9dd64733accbc69)
- Fixed infinite loop in lib/rtorrent [`370c6d6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/370c6d6f73371105315453418dec67abd03b5f13)
- Fixed issue with daily search progress monitoring. [`840f7c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/840f7c7bdfa9999a0fcda4ca1c8da72d8edad842)
- Update fuzzyMoment.js [`144a05f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/144a05ff2054d1fe5bbcffc9c72b7a5c82c9741d)
- Fixes issue of missing ui notification to let you know that there was no update needed when forcing a version check. [`753be64`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/753be6409031002b7f0eca289461836a6ca0950b)
- Logo change [`43f66f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/43f66f63cf9fa3d4364cdb398615d5005683509b)
- rawhd update [`76e8c73`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/76e8c73c4b78b82d98d0fa2d1736e8f9b98b2d45)
- Fixed issue for season searches using episode only mode but fallback to season only mode, was small typo correction [`71604b5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/71604b576994c0987623830c2e82086515479cbc)
- Path detection for icons was still in midgetspy format. [`da8e2e3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/da8e2e3d1918399e7c2ffe280577f7f14c489663)
- Update readme.md [`a6f6303`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a6f63037ab5bf5e1f9d6b8762cb5af01bc8243b8)
- Changing default auto-update to disabled, while we're pushing many updates [`48b4abf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/48b4abffa51ec6e7d2653af4f022f9539cb38942)
- Fix for scene numbering issues [`7ce27b7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7ce27b72f5944f1115b37f713ba72b44f63cfa1e)
- Fix for show_queue errors when loading a show [`5ec5dde`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ec5dde9bab216e8168dda89b6b394c9b39be035)
- Fixed typo [`cd91e24`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cd91e2430f1c7744667ce0cda8d2c0bb1dfa3213)
- Fixed backlog search details [`cd04d79`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cd04d79af5b9bb69670c516501f9ca60e7a25217)
- Forgot and int() [`c62e34c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c62e34c601b4a5052a101481bc247a9f089af788)
- Fix for missing regex module for python2.6 users [`c581179`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c5811791d0ce5975b3679aab4eb336d31c0d502b)
- Fix for missing regex module for python2.7 users [`90d0119`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90d011990c755f96a8041f92962e5d05d01b5d2c)
- Updated logo design and removed old one [`72a1e4e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/72a1e4e580bfd06acb66b641f438d7a6c4a3c8e6)
- Merge commit '8c449e2' into dev [`3a08af6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3a08af6661cf79ef765305251888a9d41ae05c0d)
- PickBestResult x264 over xvid where both exist. [`6988ffb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6988ffb82bda62ab1fffa5ab629a99f566041fbf)
- Fixed error when saving blank ratio's [`32cf17c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/32cf17c638dd6a5cddba951762e5238c1151e255)
- Fix to stop removal message of cache items from occuring when untrue [`628fe23`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/628fe23f8d5ed548bfe30030ca61e612b969f5b7)
- Merge commit '5e95c5bc0294d324ae494e88ad708648b912588b' [`82abad6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/82abad6f19aaf81cbfd4a14880f844d76ee04812)
- Code cleanup and regex fix for "no repeats" error [`8ecd5a1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8ecd5a196db7c4ef235a87c6110e91596bf5ca34)
- Database now closes connection after each query and reconnects if closed to ensure no more connection and locked database problems. [`7e0bb65`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7e0bb651b270361625b5850bd32b2247b3abc782)
- Modified DB code to close its connection if right after its finished with it, helps performance-wise and should resolve locked db issues as well. [`d00d55f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d00d55fdfcda0890c3fccca21cb29f7790ab97fa)
- Updated sumbliminal. [`8d9d62c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8d9d62caf5d05f999f51ce13990b3784617a265f)
- config_notifications improvements [`12dd9ab`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/12dd9abd5fad9ac70d74984dad4ee29dd4fdaed7)
- Complete re-code of season/episode search code. [`5772de9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5772de9eecdf6eee4204e323e8faf11f5c1c7229)
- Replaced our cache handler 'CacheControl' with 'httpcache' as we found the previous was not stable enough and was causing more issues then good. [`ce193ff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ce193ffcdb7d1cb8fb858fec586d548f83a3d49c)
- Changed to new cache handler that stores its cached data in sqlite db files for persistance [`ff1e6e6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ff1e6e6dbcf0d6782478407729f3b014b46d9f1c)
- Re-coded the Indexer cache, cache lookups are only performed for existing shows and we don't add any cache entries unless we are Indexing the show in our database so we don't waste cpu cycles and memory. [`87b752b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/87b752b4e5eb4f62038566f475cd227589c00b3e)
- Feature/config_provider_improvements [`6489905`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6489905690c86293eb03acb81fe275b38c6fc0af)
- Updated tornado source code. [`0c57676`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0c57676aedac848fc518ac1111fb25521b617a51)
- Major changes made to search code, tvcache code, and name parser [`d5f183c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d5f183c171c4b8ed1939f5aac3e8b18508ffe420)
- Fixed subliminal issues. [`c945726`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c945726f05ab2021dadeb60a48137e6ac1c75ef5)
- Fixed issues with multi-threading. [`2a4f878`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2a4f8780e2398e945967557c73fea38c08899e24)
- Fixed start/restart/shutdown issues including any issues with daemonizing. [`1fc9092`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1fc909299d80d8dbfb54cbcaeffd5d1df240ec8f)
- Lowered CPU usage even further, re-wrote daemonizer code for startups, removed misc unrequired functions from providers. [`f0146f7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f0146f728e69282dc22b6d32b53cd0fb2960cca8)
- Fixed issues with searching for air by date shows and sports. [`9384881`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9384881241b05bd2f11e349ff1c38a464d5d0179)
- Updated our cache code. [`94670f7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/94670f7f95201415f480950bc8a631b74a4f52fe)
- Lightning fast indexer searches now! [`f8ec897`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f8ec8970102bfacdd2689649add2c685f123aaab)
- Fixes for post-processing issues. [`9d191f6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9d191f69996b1ba383479a3d97c66a8d28437b06)
- Fixes backlog and manual searches. [`fc94243`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fc942435469d9901372033e4b2c90bd908c5197d)
- feature/confirmation_dialogs [`91c004c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/91c004c990e6935a716fe0c3ce578b7af960a12c)
- Fixed regex pattern for sports events that were preventing searches from working. [`1f17868`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f178686cc8d5fdb4e6b152417a5865d9353dcef)
- sbRoot missing in some img url's [`419e35f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/419e35f30069d4d0a7272dc71cff02833d06d353)
- Fixes more issues that were preventing proper shutdowns, restarts, and upgrades. [`7d52d07`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7d52d079fa00df86674de8bed8ba3ef29306dd84)
- Fixes issues #333 and problems with converting str to int via prettyName func [`afde3b4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/afde3b4c2889bcd4b257d39ccaf366c38c41c68b)
- Fixed IndexError: list index out of range issue [`1136e5c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1136e5c833694cdf5e47fee4fd497a9da7ac93a6)
- Update PNotify lib. Make notify close button always visible. Fix issue with multiple tabs. [`8514285`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/85142855302bc8fa7c61cce567365b205c0f624f)
- Provider searches for backlog, manual, and failed have been re-worked to not hammer the providers so much plus perform alot faster. [`ff5107c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ff5107cfe2155d211992537d51f33b815abb6f20)
- Fixed further json issues with speedcd provider. [`f477344`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f47734446d1546fd013566b71cf67fee94dfae58)
- Bugfixes and improvements to our code that converts regular sickbeard.db to our new indexer scheme [`c97f5b9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c97f5b9c702ed91f55a67e0cf7ab6486e29e0c53)
- Bunch of code upgrades and bugfixes [`ce5053f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ce5053f25d54cd1ee49045cefdf86c04fee2998c)
- Improved startup/shutdown of tornado. [`abff43f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/abff43f5680865470fd7f0c38354df595e774bae)
- Fixes for backlog search. [`b33e2be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b33e2be0478d06883f4c1f8dc54412050c278321)
- Fixed failed download handling. [`59675f2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/59675f27ac7584746b3138acb3de28314a8602fd)
- Fixed issues with post-processing, we now perform the auto-detection of the indexer in a spot that doesn't require the post-processing to start all the way from the begining allowing for less processing time to take place. [`c330bbb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c330bbb3863dd44adcd08808b039a5f096a3a2c1)
- Change how the "local/network" setting is handled to address some issues. [`732009f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/732009fd98e6f3d718a8a80913726e8eee561b89)
- Replaced provider backlog only search option with 2 new options that allow you to enable daily searches and backlog searches individually per provider, default is enabled for both. [`bcffc09`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bcffc09589297d6a7ab199dc75febc4ca3783434)
- Fixed issues with webroot settings and reverse proxies. [`07685f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/07685f4295007a79da81dda33e93829403f3614f)
- Fixes issues with findpropers and airdate. [`a5b72de`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a5b72dea8424420e81392660fd0a04e811015e9e)
- Fix for daily searches and high cpu usage plus increases search speed [`67bd1a9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/67bd1a9e983d174912e378690e359ac1c070c403)
- Revamped the failed handler code to fix a few bugs and have everything failed sent directly to backlog [`748ba6b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/748ba6be71cb325985cbfb0ae0e5ca7fd301b500)
- New event queue system in place, currently handles shutdown and restart calls. [`74f73bc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/74f73bcc34da09e1406d93b8a19438b0075302d6)
- Fixes for thread naming issues where provider names are getting stacked on top each other per loop iteration. [`b16ff81`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b16ff814788afb6e51d4e3da9dbc6562091cc66c)
- Minor bugfixes and improvements [`fb22290`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fb222902c108f60c501a40f5ad1a403876859f02)
- Cache issue fixes. [`dbe7e01`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dbe7e019f684ed42887d6dbf6a4ab1dbe9ce34f5)
- Improved tornado async routines and shutdown routines. [`20e2ae2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/20e2ae2f86fd3561123d855921d235c1bce9a631)
- Fixed issues with restarts and updates. [`d835888`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d8358882de75305749269e90e91c8b9529c09605)
- Fix for air-by-date/sports/anime provider searches [`05dcdd7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/05dcdd72d7771775034f22b07c49c660b48db1a1)
- Fixed alot of issues pertaining to season pack searches and backlog searches in regards to returning accurate results or no results at all. [`dea826c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dea826c3ba54b89ed03e1d3b0e7e87d7272bb389)
- Fix for extensions being stripped off by mistake made when adding in -RP fix from few commits ago. [`5ac99b8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ac99b8c5c1555ae4252f4677ea1afa2617ac899)
- Fixed NameParser to properly parse anime episodes that use normal season and episode naming conventions. [`a697805`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a69780592330493d6d201c7498365939afa295fc)
- Fixed main database structure to line up with original sickbeard structure so that migrating users get our database modifications migrated in without issues plus I've updated our main database structure to reflect all our recent changes so that new fresh installs dont have to go through the migration process [`09dd1b6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/09dd1b6db281242dc61d8a19ce210196fb17cb7c)
- Fixes issues with tvdb and tvrage api content attribute not found [`f54a6e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f54a6e25b258151ab00c1b724069166665f2bf44)
- Fix for startup issue when using python 2.6 [`3cefc5b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3cefc5be8697828e879785a0314f09ee1ce1e0ba)
- Notify on update for notifiers via email has been disabled for now till we re-write the email notification code better, fixed a few small errors here and there. [`c34442f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c34442f5c19f419654a6fb48b813b37b0c14d26f)
- Improved code for better performance of application memory and cpu usage. [`0947622`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/09476224c58bf49ad1f9a8e1602306633b40f1e4)
- Bugfixes [`90cdf32`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90cdf326b7eb90173c3dccb243fdcd299f23eab2)
- Maintenance tasks are no longer blocking startup. [`c478d45`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c478d45c3645049acd17a5a83304f41253e15ce8)
- Fixed broken layout for anime black and whitelist [`8135a97`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8135a97d62c27a3e792a5f6cf19e685960639649)
- Reverted some changes. [`75f6939`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/75f69396d4ce75681e9f4cfe5e8b368ac539dabc)
- Fixed show name formatting issues. [`4f049f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4f049f4e7ec8fd520307080bf6c89fc8743225aa)
- During backlog/manual/failed searches we now cache disgarded/ignored results pre-parsed for usage later on incase we end up setting a episode to wanted that matches said results, allows for maximum performance and helps limit the waste of resources used. [`3a2b673`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3a2b67330c1b2aaff8f383aebacad483ee937b73)
- Fix for air-by-date and sports shows issues with parsing results. [`be17ed1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/be17ed122bf39edc84ee2cc87b594d6f864fefa8)
- Updated libs to include new pyGitHub modules. [`9abe5ea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9abe5ea859e7e73552f1eb5d6b6fe8c3bf205e88)
- Updated post-process code. [`08159e2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08159e28722d4836f17c97b6f897103707a14985)
- Fixes for DB issues [`a1da7df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a1da7df12ee1f5fc84205c6f08861c448596701b)
- Doesn't start a scheduled task for things not enabled to not waste resources. [`b1de2c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b1de2c7080185d930e6c37000b77ed432af07ee0)
- Post-processing now auto-detects the correct indexer for the show both on manual processing and script based processing [`22a4a06`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/22a4a066d8c9868e0837317d5f9a13684f220d87)
- Fix for addCacheEntry [`450d96e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/450d96e0413f095977f3d4bfc534f84b57145ee2)
- fix for date clipping on poster view [`362ee82`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/362ee82c29a2d50fbb2c90b7723dc83c32ca3993)
- Fix for debug logging on console. [`99bbd06`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/99bbd0649cb0ec86c688f6c2495c15fae4a1ea01)
- Fixed issues with trakt and root dirs. [`2d0c315`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2d0c31510eb021d4c9df87b142edcf24984c72b4)
- added indexer selectbox and timeout in search [`ac82e32`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ac82e32b98fb25804e335515aa578111589fbb5b)
- Mor bugfixes to code that handles converting sickbeard.db and cache.db files to our new scheme. [`264f852`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/264f852a971dca0f70e4edcbfcb958c31e29384e)
- Removed maintance schedualer and moved the routines from it to happen before a search is started to ensure things are up to date and to stop waking up synology devices, regexes also made less greedy. [`c8d899a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c8d899ad669ea8111bffecd482b5e0f3bde644eb)
- Code cleanup and bugfixes [`bbf9491`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bbf9491943df4af5dc43d46166f0e8591670831e)
- Fix for root dir location not being saved or set correctly for shows. [`79a1b1c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/79a1b1c31e419d0e6ed584a056f1806b9a21951d)
- Misc fixes and code cleanups. [`08d8bef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08d8beffa431b2f855b1811bedbd508fe7e284cc)
- Fix for newznab provider settings not saving properly [`3cb1c57`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3cb1c573a3166f747ac1dd0880a12256eebc81da)
- Fixed errors in scene exceptions when retrieving list of exceptions. [`70c2a2d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/70c2a2d130ffbd4d146a491798d02e6b77ed3df1)
- Removed all scene exception memory caches, fetches data from DB now directly. [`adb4715`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/adb4715b3eb2ae8fad5f71aadd9842142afb218a)
- Fixed issues with parsing release names and naming patterns including regex for sports is now more accurate then ever! [`3a60683`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3a60683327bf0561354bab0da8e46a057f90fc38)
- Improved XEM scene numbering converting. [`43b6b4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/43b6b4b5949a24ef6982575096cd72bea7f1eac0)
- Fix for 401/404 errors now just redirect back to home page. [`fd88c77`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fd88c77d2698826a48d26886e16640a8f3e504b6)
- More memory reductions and cleanups [`5e507b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e507b384989b549295f736bc753f26f2e66c3f5)
- Fixed manual episode searches. [`7e800ff`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7e800ff5242cc980e9044f8ccb108bd146ae1322)
- Moved code for cleaning up cache folder to seperate function located in helper.py. [`b13e72e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b13e72e0a35ee67f9f2a0f1ba8c5e9904632cc0e)
- New searches now search only the indexer specified when importing existing shows. [`d0ac293`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d0ac2936b040abec2a995fa61c8453629b06dfab)
- Fixed up code for searching indexers for show id which fixes a bug that was present in our post processing code [`ab12415`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ab124158a4178e471ff9400c888a060b94b1cf5c)
- Implemented the queuing functionality also for Failed downloads. [`bdac98d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bdac98db4b8d8962fa3d9deea200c42899c01b73)
- Fixes for a few provider issues plus passing of search_mode variable. [`af0ccd6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/af0ccd65cffc9c28082451f596336f8bc2c26070)
- Fixed massEdit issues. [`a15258c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a15258c784e5e84fccf441905ea253cd8fc7ad1d)
- Fix for no providers found error during searches. [`012baed`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/012baeda0cc9270234ddaa52f56f8e88172198ce)
- Quality is now set during parsing of results. [`24dfbc3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/24dfbc3f15c7a708b77d983f5e3e5ecc4cf3b7dc)
- Fix for trakt.tv issues when adding/removing/syncing shows. [`b8b5947`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8b5947ae65a2e673fe775c84b1b7c3d92d8b4a8)
- Re-coded our cache session handler and made vast improvements to it [`381049c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/381049c3739b01071b2db85cd28e7353a3a18c35)
- Disabled sceneConvert renamer for now till we add it in optionally. [`831e9a5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/831e9a537e6632549c0fb080cd193df4cecd2eeb)
- Fix for threading issues with backlogs and whitelist/blacklist issues for anime shows. [`5bc775d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5bc775dfb9ea9c55e4e3cb867ef1c0563a25e909)
- Merging changes from Prinz23, PR#156 [`b177c1a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b177c1ade29d2bf8afbe2acd0792cd241694d871)
- Fixes more issues that were still present for season pack searches and air-by-date shows. [`b349bab`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b349bab56993a4ac94330d3406fcd5f5f3d7e904)
- Fixed backlog issues and improved cache and provider searches, this resolves issue #298 [`1c6b080`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c6b0807b0a1941703823d6692ddc2b3a742352d)
- Updates/Restarts now use the same process instead of spawning a new one so the PID remains the same. [`386355e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/386355e1302404bfb239efc8324cb41d9a80f3fc)
- Updates to auto post-processing code, additional code added to ensure indexer is always set to the correct value [`6a4adce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6a4adceb26d06136a931dca0321fae102c270e5a)
- Fix for NameParser invalid show errors. [`fefcfa0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fefcfa09529e995e7c0c3852ae5eabffe7038de0)
- Fix for saving default options when adding shows. [`2ab436b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2ab436b764e1c9a4f65ccf16d204d98462289276)
- Fix for air-by-date and sports shows [`35f70c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/35f70c79242c45ad8d77c21cb6e91887bc9c8f5d)
- Fixes for updating/checkout of source installed versions. [`281c5c3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/281c5c333edced4f95c37e8d9f89aa3004d088ad)
- Fixed invalid naming pattern error. [`7cbeef5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7cbeef5ed0c88a319411ad9f2e804acc8c0697f7)
- Fix and repositioned show_message on display show [`9870d09`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9870d090d3da8bc0c6a9d6bd54b79ab2b4d52ac3)
- Name parser performance fixed, manual searches fixed. [`ac9d78b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ac9d78bc0f8778766b068133b7690e6a354a154f)
- Fixes for anime regex matching [`99d129b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/99d129bd414f26ec998e824f007c3b0d55edb423)
- Fix for sports naming patterns [`160b4bc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/160b4bc4ccd63cfc0f90e4ffd1d4d2dc4bb688a6)
- Fix anime legend table on post processing options page [`c19d5e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c19d5e1600b738eec82bf017a3ae14682ad93f47)
- if nothing has changed don't execute the transaction for network table and don't reload the table [`6adbdb5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6adbdb5e8679edd2214b0b9638a3857be166d109)
- Updated scene exception code for checking when last refreshed. [`c25da85`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c25da850ab9b14706dfdf5918f3b0c084c76cfbc)
- Fix for issues relating to adding existing shows and nothing happens. [`20bc926`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/20bc92650bbf9f00139964511c8f308c4008040a)
- Updated readme.md [`75b6d2f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/75b6d2f51ad27e7d0558bcabb8c051a70918da97)
- Fixed andidb scene exceptions to be called only on shows that are marked as anime. [`79f923d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/79f923dc9cf6dba3fe0084c0a41c71cb828da44d)
- Fixed issues with web root settings not working. [`032ddf2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/032ddf24259a7e6a4b3d4c3bb49dd48921949e22)
- Updated readme [`e8556b4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e8556b4c05d2d7607da244eb5b26e77ed7f0c119)
- Last set of fixes to correct this problem [`33be932`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/33be93288a243a44bf84e640f98bf3890fc337ee)
- Fixes cache issues with lookups resulting in wasted cpu cycles. [`3fbfed7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3fbfed7d93ebe44350f03b58308b1e8e8850ad87)
- Updated cacheHandler to allow us to force cache and set a max-age on the cached content, vastly improved performance with indexers. [`40c69d6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/40c69d6a0f15f152f0ba77ea13917c1efefe6201)
- Fixed -RP release issues. [`02c8b86`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/02c8b867c654871fe202b9bb0458e46da93594eb)
- Reverted persistent storage of nameparser cache, testing fix to prevent crashes possibly related to memory usage. [`546f7c0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/546f7c00b4ab6e8eed214b1d7514bfb6f3f384f8)
- Fixed issues with popup notifications. [`96fa095`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/96fa0953e39b0523ad47bb3f7b76d6de7f29e441)
- Fix for feedcache logging. [`0e962f8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0e962f83cbd2d6c79d3af6bf26024bfcd2c14b00)
- Fixes issues found in cache and with season pack searches [`5252cbb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5252cbb72ceb500c3bd53bb12d85d2971380017b)
- Fixes issues with scene exception updating when editing a show, should resolve problems with it duplicating scene exception name over and over again. [`636bbfa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/636bbfa2de373e16235e9cf81a22888dd216c449)
- Upgraded IMDBpy and improved performance of it. [`cfcc35e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cfcc35ebcc9fbe139e48c9d45d3ac6eecf5ea02e)
- Resolves issue #13 [`aa86671`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aa8667106f1b16a7d2b2700fe2b23d3faa3d3961)
- Bugfixes for post processing code [`45ba1e8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/45ba1e815b1f8bbd9aaca27b09c5ccabe9d3c578)
- Fix for setting status via episode status manager [`acadce4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/acadce4d963fd902945768ca948ebefee7601a48)
- Updated readme.md [`ea2ec23`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ea2ec2390a59c086f93bdc5e56396d862622fa89)
- Fixed whitelist error when editing shows, needs more code changes to fully function correctly. [`7f20f5e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f20f5e27f2e68bcdeedaab128404c7eef75c30c)
- NameParser now trys to obtain a show object first to use in determining the correct regex set to use when parsing release names [`4ef8896`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4ef88961b558e2bc3dc474a21835f41e854fdcb0)
- proper settings for proxy [`484dba0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/484dba0de852ce8b055e71e8c20e7d4dec0f432e)
- Fix the home page from failing to load if a show status contains nothing. [`59f4f44`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/59f4f44edbe094c3d6fac308f387a80263b9cbf2)
- NameParser now won't bother to proceed parsing release name results untill it finds a valid show object in the DB to confirm its a show in our list, naming patterns automatically bypass this restriction. [`fcc91be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fcc91bedd928f4f9c37a4e3650e59e694093e555)
- Improved startup and shutdown for tornado [`6dd78f5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6dd78f58b6f391bb810db3a06156bb7546f0eb35)
- Fixed issue with main database migration numbering [`fe10a45`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fe10a4551e53d1367d17b00d52050475fc90b761)
- We now check if a torrent url links to a valid file before adding as a verified result to get snatched, this helps prevent issues when attempting to add torrent to client later on to find the url returned nothing resulting in a error. [`19a89d4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/19a89d453c790e51d10172b3aaeb3ddefefcd696)
- Fixed Name Parser issues, incorrectly matched current regex used to parse results and anime patterns didn't match 1 to 3 digit numbers for absolute. [`3f6084f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3f6084fe4bdb3fa50513c3cf12098b1af6fa8b0d)
- Fix for nullhandler issues for py2.6 users, [`98ff924`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/98ff924b1c85ce19773bdf7b279d5110438ce2d0)
- Multiple bugfixes for provider code [`ad339a9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ad339a9b2e25b85a68889def0f7fe94e8ddf90e9)
- Fix for __exit__ DB errors [`61e1e5d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/61e1e5d2c26b1e396b95b82d088aeed68f15d599)
- Fixes for editshow functions. [`d916958`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d916958abc4bff8ab11c0b8731eed53214ca7674)
- New show search code changed to optimize for quicker searches [`872389d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/872389d055fee1a82c48ab518472d3514226b886)
- Fixed naming issues for episode naming patterns. [`7047cf0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7047cf020ef9ce8971852d7936428127a88d5922)
- Fix for post-processing and parsing errors. [`f91569e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f91569ec848ab335944cf424318218f1d8d0cf52)
- Disabled caching for notification tests. [`1145f90`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1145f90208afb4fa8bec731a112826c1239cf11c)
- More fixes for checkout/updating issues. [`39fe8e8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/39fe8e84778edf67d092a149e3c656d7ebd3179b)
- Fix for issue #290, Post-processing issues [`85a9a81`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/85a9a81f4e5848a9c274ab3c761854599fe63453)
- Fix for air-by-date issues [`28d39df`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/28d39df816876efda40dc2d9d90495af403d7fe1)
- Update pp_tests.py [`94f60e7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/94f60e72966e01d2f994895007f3282d79ee3063)
- Update pp_tests.py [`81ddee4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/81ddee4760202407886a7f54ae4c140458eaf559)
- styling fixes and clarify what to do after theme selection [`d475ee8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d475ee82c840e8361320549d72ba9e77c29ac3e8)
- Fix for migrating to new newznab and torrent provider config formats [`6fd19de`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6fd19de7e23627785b31283c6d3d69c254f80181)
- Fix for coming soon episodes page. [`7e5cc8c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7e5cc8c6736b5d67fd2405de8e970fbad0d1c34f)
- Fixed issues with added new shows not showing any episodes. [`9084d7d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9084d7de199dd023ab9e712f1bc0a9400a51cc70)
- Fixed bug for returning requests object exceptions [`23348e0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/23348e0bd0d26f6ab258c113de8925733c9b582a)
- Improved newznab offset code [`ba4b408`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ba4b408af315e126bd9bd3403563878d6cd1c7dc)
- Fixed regex patterns for both show and release names. [`5c5b6f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5c5b6f49e1a89090c46cc43bf7b908ceca8da2cd)
- Fixes issues with scene numbering being set to 0x0 after snatch is performed. [`14201c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/14201c71f3b6c7ad71dddeeeaa59fe22347d8023)
- Improved newznab offset code [`ab16430`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ab16430b1ad9affb77cfe6badcfcf8a2e28c4030)
- Fixed failed download handling. [`64b857e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/64b857ee57ee65e5547143ad428186a74632b24a)
- Fixes issue #326 [`a3bdf60`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a3bdf6038f00fc187dc6cc4c13206f09621fbf62)
- Fixed issue #221 [`f6cf80a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f6cf80aa99e364dccde73bf7d09173919d620ec3)
- More fixes for strftime and findpropers [`77bc5c7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/77bc5c7291b88b962efeb86adc1a0cadd1de38c9)
- Fixed cheetah's template subclass to properly return correct line numbers in tracebacks so that we may properly debug errors. [`ab69e52`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ab69e526159150ea9b3bdaea994c92d42d1a9065)
- tvdb_api update, backport from midgetspy [`ab89084`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ab890846889b9f98afb29e1ef648aadf09507c7e)
- Fixes for air_by_date and sports shows [`eabd0d0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/eabd0d092f2d2d6e3498ab05dd2a366dbb4f5a39)
- Fix for subtitles datetime issue [`56a0a04`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/56a0a04a2cc28787b9477b6a9712d3e0ba140c3e)
- Fix for updating issues [`f9ababe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f9ababe7cbf54dd822f121138a62b3cdfac92c89)
- Fixed shutdown to completely stop and close IOLoop. [`acca01e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/acca01eb90b1162a0ee5b78362c97df14ff60b73)
- Code cleanup [`6967a8f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6967a8faef5b889b7ceb2760f8d9afb057c6c560)
- Fixed a few bugs. [`b0426ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0426ca12d82091f158abfa89802294ae50ee5d2)
- Newznab providers now search by tvrage ID if available and show name incase tvrage ID doesnt return any results [`ea66c2c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ea66c2c41be7b9e68e1b3a7828b663b635bbdbe7)
- Moved show season/episode cache to outside of the show class and turned it into a global to avoid circular ref that may memory leak. [`89ad4bc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/89ad4bccc3415190f193e70027c05cade6cb6ff4)
- Fix for bug #911, escapes regex for ignored words [`461b1d8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/461b1d89d354e640151cedb71167bb559fab7075)
- Fixed issue with reverts to master on startup due to bug in version checker. [`7cb2296`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7cb2296b6a7192f2f2abff6a32cc6cd80a5add2a)
- Moved code out of series_name check for show object creation/checking. [`09a3333`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/09a3333399d0556f621503bd1333c9bc2f473d7c)
- Unable to parse filename errors are now set to show via DEBUG logs only to prevent unicode chars from causing misc beeping sounds ... [`933fad2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/933fad20c7ec25158ea4df6d5cee99823e483e68)
- Combined 'Delete' and 'Remove' buttons in to one on the individual show pages. [`b9b88b1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9b88b18a67ba96db5db787feda7e5263103e970)
- Fix show name matching, trys main show name pattern then if no show object is retrieved it attempts using the alternative pattern. [`42e1994`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/42e1994cbaf192fc5a9e7a1de035eed4da75929b)
- Fix for missing column 'subtitles' during migration from other forks. [`ee6e55a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ee6e55aa8897a088c380b9d60c6af7561fd2a1b8)
- Fixed issues with torrent blackhole download issues. [`9761c6c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9761c6c6a37228ad2c7935f3f0032d72c93fa636)
- Fix for pushover notifications. [`8dd4585`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8dd4585145b37067d34751198b35de10483b446f)
- Fixed naming issues for sports and air-by-date shows. [`818536f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/818536fcb4587199cc0afaa856afc597fd01da8a)
- Fixed bugs in cache control [`2acafcb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2acafcb603af74e4c9a6fc62523136d74fd6f7d5)
- PEP* Cleanups and added timeouts for threads when shutting down or restarting. [`cef53be`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cef53beee02840bfc735523894dd23050d4cd61a)
- Fix for closing cache connection early when needed. [`1f180a5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f180a5a05c38491db1589c10a1dae7bb5f72376)
- db lock issues fix test [`26f30ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/26f30cacf523de798b74e2dd7a9c5a587aa26770)
- Fixed high CPU usage during searches, adding conditional check to prevent un-needed name parsing of search results when search result was previously already parsed and checked during filtering of bad releases [`65eda93`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/65eda93b2b7ea4b9629f50cdd12f808a61437ed1)
- Fixed memory leak in scene exceptions. [`0a80d0c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a80d0c3dd9194a5a98ab44256f861eb2c4c1e42)
- Only process if there is a name present [`21b7aa2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/21b7aa27850038387b8ac6632d5283ddd4217509)
- Fixes issue #25 [`f2fb907`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f2fb9076ad585191b9de4b9eb10299d5d7f342a5)
- Fixed another issue in showUpdater. [`fac97e5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fac97e5f5a37339d40c0cb70a66def94e2704719)
- Fix exception for when no results returned. [`8b67844`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8b678445cc45638d3c2ab15afe6901fbe7e0ec89)
- Fix for trakt connection issues. [`4094e2e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4094e2ed3c678ea0c59de894e8994319075af757)
- Forgot to add check if naming pattern was calling nameparser for previous commit. [`2fec443`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2fec443c37f65a8372d8d32e82ce8811a75c3d49)
- NextEpisode code modified to return the airdate ordinal instead of a ep object, faster. [`dbe22b5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dbe22b570b87d2c1408a7b0622b77786e55fbe5a)
- Fix for pyGitHub module not found issue. [`4d41d88`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d41d881eb1a2cfbb5414366a981148990749e2b)
- Fix for subtitle processing. [`1b84c6d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1b84c6d28102dd525168a893ee5ac977539987be)
- Updated nextepisode function to only perform db calls when nextaired date has been reached. [`5237e70`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5237e70fb3cc46a8dafdb5e3afa181d509f5ec89)
- Fix for db locking issues [`d30060b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d30060bf9119994b55c9fae86f60839674dcf530)
- Fix for sports naming pattern issues, finally this is resolved! [`a97dcad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a97dcad291db66fc3e3fe66758b898d4eeb4e378)
- Fix for error code checking for Newznab providers. [`71ec47a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/71ec47ae6b7e8d817e45b90ec9845f5fe5f99e01)
- Fixes issues with backlog overview page failing to load [`8dd822c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8dd822cef010960ad8588815abc9801120cc3a87)
- Fixed forced updates to wait for auto-reload instead of performing a restart. [`2ac1c5f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2ac1c5fdd5813d9e8797b5733958f105d5c2aabd)
- Final fixes for proper shutdown of tornado [`149d7b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/149d7b29dfaebd81a61e2cef755e63c650436ac5)
- Reverted episode cache changes [`44358ef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/44358ef60187ea4f390ec80e31dff42c9140b53c)
- Option to prefer single episode releases over season releases: [`84120ee`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/84120ee00e09e20acc1b88ba2bb5e9c1d4e71eac)
- Fix offset calculation. No more unnecessary (double) searches. [`fd4e267`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fd4e26795f8c870d6adc228467b0c9958f950142)
- Disabled logging of tornado.access [`53e7c53`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/53e7c53b8afd9c1cdc00b58667b5556892f511d9)
- Fix for mass updating not actually changing any show options when editing [`272ecd0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/272ecd0ab8241a6f37e2936f5cdfc742c225cd90)
- Fixes issues with searches and importing existing shows [`a71ed25`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a71ed25b198d4ef76cb254c720dd1cc334d187e2)
- Fixes other temp tables that may have been left behind from a bad migration of the db [`5dbfc81`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5dbfc81bb2f55c8c8ff5f510d7565b8e9c420210)
- Fixes issue #25 [`896805e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/896805ecb20d22e00e33618462dd2eba253d27ec)
- Fixed issue with new show searches not returning any data. [`e19e0e8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e19e0e8d1cb57ed1ddae0d42a248f08b20f23296)
- Fix for bug #903, Fixes issues relating to proper and repack provider searches [`238df07`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/238df07c1dc767f82143bbe6ef7911536d48df22)
- Fixed adding of trending shows. [`1c46813`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c46813e89e569c2e56ec5e6ca10bb30bd5c6f03)
- Fixed some git conflicts [`8b4bb3a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8b4bb3a5a5f50c89aec1003cbe56b71795e06b0b)
- Fix for anidb errors [`a16bf8c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a16bf8ca2cf0adbb1ef60d3a521c332ce8db7521)
- Removed tornado's auto-reload function and reverted back to using our original method of performing auto-updates, this should also correct 500 internal server issues for those that got them after updates where performed automatically. [`b6e7635`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b6e7635a32d79216ec7350d7629b1523d66a1629)
- Move some code around in our cache handler for better parsing and accuracy of caching [`1bb9413`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1bb9413b19bc91406778f5fe79a8d7d7a72a4080)
- Update changes file [`0bb60c6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0bb60c6d1c1acff7fea6a98ac95492da8d23b78e)
- fix for ui-pnotify [`f97507f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f97507ffc7b0f706c9f2489dcad00df83d887213)
- PEP8 changes for rss feed cache code [`45fc163`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/45fc16343448c79b787104a81197e8a2b52ae4f6)
- Fix for files being deleted from show folder during post-processing runs [`27189d0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/27189d0406ba768126f1d618e778b62fca19c264)
- Fixed DB issues related to displaying plot details for show episodes. [`f6c40d4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f6c40d4b251706a84df34886f8de10f0d9b3b711)
- Removed tornado async features, testing to see if this resolves blank page and other related possible issues. [`2f73ab1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2f73ab1e41d9d713fafeb8fed9237ec4690f8b60)
- Fixed issue with extractZip function. [`5f7b846`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5f7b8465d05279a5a9dab01f28d9fc02e104ba81)
- Fix for config page issues. [`ecad67b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ecad67be06cc899a5e10eeef91817b5ddeda55a9)
- Fix the Plex notifier [`0077a8e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0077a8e5182892183845f18ead1c95ef40c60404)
- Fix for missing indexes [`a7ae6a1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a7ae6a19771fbd5d0fda3caab67bbbfb4fd0ac4b)
- Filter out possible torrent links that would return a 404 http error [`11150ef`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/11150efab05db66348cc40333599591ea68ae17c)
- Fix for scene exceptions error. [`0e665cb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0e665cbbb204f08f4fd952e4c206e2e55b9d48a0)
- Fixed language and subtitle issue for new shows. [`9e4ee04`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e4ee04f577a91283b9af4898e9a66ca07e38c8e)
- Fix for string issues [`308add5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/308add5a1126fc7459a15a304e9c1da45609336d)
- Fix for index out of range issues [`2893b33`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2893b3331e64720913d42620e01690ed3f968c58)
- Fix for formatting pattern issues [`f9cd37c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f9cd37c2436e929a7d313d127eed038246708188)
- Conditional check bugfixes [`e171aa1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e171aa1c1098e45a89ecf15ed84b15b79ca5af68)
- Fixed bug #895, automatic post-processing not being enabled when setting enabled from config. [`b1d7cdc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b1d7cdc1ad2ff9206044370f6621069359277cce)
- Backlog frequency determined by algo that takes into account daily search frequency to prevent overlap of searches, automatically calculates allowed minimum value that is user-settable [`e78392f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e78392f04ab8b3ae9367f70eb176218c0d055586)
- Fix for newznab provider searches [`f65262e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f65262e0e9e3207ad90886c95f487273068748d3)
- Delete files after it performs copy/movie/link instead [`872dd2b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/872dd2b9fc9f90dfb35ea4d92904b5d68c735bbf)
- Regex order of placement in list now taken into account when scoring matches. [`20456fd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/20456fde6be3cb1215a8e149f1b375bd672dfd32)
- IOLoop tasks are now started and stopped via regular start and halt sickrage functions allowing us to gracefully exit on shutdown or restart. [`fa01711`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fa0171119248547dc6eddce233d330b00db73f5a)
- Fixed issues with finding propers to many keywords. [`7f44a2c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7f44a2cfadd17d0b6a968aa946b0c9891585684c)
- Fixes missing indexes for tv_shows and tv_episodes tables [`fdfc8eb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fdfc8eb2199d0b9450333862a9c3a5b322807aed)
- Fixed trakt library update issues. [`cdd190e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cdd190e1e7b98f9781b9fd3160fb72b0134a8979)
- Fixed dailysearcher to only update the cache results for each provider once at start of the dailysearch routine instead of per-show which was wasting cycles and time. [`301f124`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/301f124cbbb9cf3d94e480ab07022e9a151a6fab)
- Implemention option to start/stop full backlog thread [`d76c9d1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d76c9d1c3b5bb026f06b4d252be8732385a19d4e)
- Fix for bug in comingEpisodes template not properly displaying [`3534574`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/353457474119d3f8aa5915e987370a2a97b15d73)
- Bugfix for scene numbering and kickass searches [`e3a843a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e3a843a82391719d321bb7e021b505320ddbdaaa)
- Fix for Error cannot find 'cur_ep_enddate' [`a3449db`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a3449db3d36f4880299edc087adc5a58e659e569)
- Filtering of torrents with 0 seeders is no longer forced, filtering now is done strictly by min seed and min leech user settins which can be set from search provider config settings. [`09f53d3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/09f53d3537238dea86c25937840c20f0d0ef6957)
- Fix for search provider config page errors. [`2d87de0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2d87de0fd8ddbd013fddd3c9ef5d98df764dbfbf)
- Fixed backup/restore issues, uses correct data directory variable now. [`10bea52`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/10bea520a7ecddde9f1326da81e82b07e9909ee5)
- Fix downloading from foreign section [`27fa146`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/27fa146724076f343df7032c7d2a15c2d2abe334)
- Fix for sql mass add issues. [`fb0339a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fb0339a274154deb3fb41c7dcf3d8a39f88d8303)
- add checkbox to control proxying indexers [`5aae8d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5aae8d7b4872cff67646fc67d7a9a50cec295404)
- Fix for newznab provider searches unicode issues [`4b66027`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4b6602797fe71c7396c30fc0e980c2fe09da67f0)
- Fixes issues with indexer_id never being added into tv_shows table when at a db version of 15 or higher [`c373844`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c373844d87b06b5461a4fe85cb2eb6f33919f5d2)
- Update Config info [`b38bf52`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b38bf52c4d94ff7b15bd1d10413daf1a46bd914c)
- Fixes issue #376 [`faeb11a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/faeb11a9ac65402d2f654dd18b4b916b338d97f3)
- Fix for issues downloading season packs and episodes and multiples of the same episode. [`a2a608e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a2a608ed856cc42fa0e380463bf6276f27c9ef36)
- Fix for indexerid issues with cache. [`19cf543`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/19cf543693215f8a2197ed88eafa8956e7850969)
- Fixes to metadata parser [`b435fc9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b435fc9d71ac7aaada7ddce84ffd95e8c3d968f3)
- Fixes some unittests [`f4ea244`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f4ea244dc94dae11236d3fddf7611c2637e18f36)
- Fix for updating/checkouts when using source files instead. [`650862f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/650862fafce9964f259d7937dc958379f633365f)
- Quality sorting fixed for provider results. [`6f817c0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6f817c0c5cc63a1a2ec538ecbacf6433425fc44f)
- Improved and faster nextepisode function, speeds up home page load times. [`a085f0f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a085f0f5382a2947e28058e1e22f21dc31a99146)
- Cleanup leftover fd sockets on restart [`33a28d2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/33a28d20a301ffece608e950a485b32f662f39d4)
- Logging for tornado.access is now sent to NullHandler so it doesnt complain that it has no handler, still disables logging for tornado.access [`38edbc8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/38edbc8b8b2360f4733b77c0a2420071e6e0b55b)
- Fixes issue with update frequency. [`b0ec12e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0ec12e4217097a65d7622560005a18e0e23d968)
- Fixed to use tvdb_id from trakt api instead of indexer_id which is not given [`1f03d1c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f03d1c2525482081da9625602ba845108c35d92)
- New show searches now try and return exact matches first then next best, search speed vastly improved as well. [`3af9e2c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3af9e2ce6596bcb870e789c4a3aedb8bc4743bbe)
- Made improvements for searching for anime on newznab providers, who haven't straitened out there anime episode parsing. [`d0dac45`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d0dac45315f717efbbc9e7fa657e6f01ef3b29d7)
- Updated code to perform indexer id comparisons to confirm show is correctly choosen if we passed in a show object to test against. [`bf40e6b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bf40e6bd98c64ee26eba2741eee3cd13900ebd86)
- NameParser now gets episode/season numbers for anime shows using absolute numbers. [`c3f6417`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c3f6417f5f08235557ce53118f7476d6154f67d8)
- Updated next episode airdate function to be run once at startup and then each time after that with show update schedualer [`d6225dd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d6225dd8d395599533b3a157ab8e0342e5cdd5cc)
- Fixed duplicate tv cache issue. [`cfbb767`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cfbb7678a9bd0bbec8c9d28eeaf0717c13b9434b)
- Fixed basic auth issues. [`04681b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/04681b329766858d9170b99dd2f5d1eb2a313d09)
- Fixes corner case where cookie could not be found [`23b991e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/23b991e9c9c5df3fd3414248699f13d49bf12db8)
- Fixes a few more issues with backlog searches, relates to issue #298 [`5a1823a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5a1823a15a1f279a45aad477a37c7a430103788c)
- Fix for country codes not being properly accessed from imdb causing no icon to display when looking at show info [`0cc5ba4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0cc5ba4eb75f209ed7b53393c3a18a3276098c21)
- Building of name cache executed now at start of searches to prevent building cache for show more then once when not needed [`627debc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/627debcf88632dc90e660ed28024a69b53a2ac46)
- Fixed global name season error during searches [`20c0b4e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/20c0b4ea720ab2c3ff3e721020a95bad297183f8)
- Fixed failed and manual snatches that where causing WebUI lock-ups. [`c423d34`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c423d349e880ab1e473e55654f1282ed1b331d01)
- Patches the enzyme lib to allow the detection of subtitles embedded into mp4/m4v files [`2c94f9d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2c94f9dd82bd243ab3e6e3d2b7df9d9a2cf8e080)
- Fixed "show must be added to list", regexes now check if numbers following after the series name is a date or part of the series name to properly parse and return correct show object. [`2c98a5a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2c98a5a448932ce40df6b78292c2364c58c69d68)
- Fix for reguired and prefered ignore words. [`07cee09`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/07cee09c83ddb50350d2d2057715fbf8552b3750)
- Fix name parser issues for unitests [`60c0399`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/60c03996a626ad022f49b92c3e820d70bb42ae9c)
- Updated sports regex pattern for more accurate matches and to filter out pre-event episodes [`dbb3b75`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dbb3b75d6e52b84cadcb6733a6af4fd99d9fcccd)
- Fixed issue with threads not exiting on shutdown properly. [`b484192`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b484192390ff5b088732dfcf9cb70356bfd5706a)
- Fix for incorrectly displayed remote branch list when in advanced settings. [`a8bcbc6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a8bcbc66c37fe4b0020bc6aab364bb6f3795b66d)
- Fix for scene numbering during post-processing [`dfd6f38`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dfd6f38cfe916705e54c0f7e8c0e021dbcbd97df)
- Couple small code fixes [`2550b8c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2550b8c831fd7b5d2040ac3a87bfb657c8cc1936)
- Fixed bug in backlog search for wanted and failed statuses, was improperly loading our segment lists and dicts. [`08f67e0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08f67e09de5aa56a8eb44c762b1aa5a86b18b528)
- Resolves problem for display country icons if show has more then one country listed for it. [`0766dfe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0766dfe3108b0769487d0d6934a7f1eff599c5b9)
- Improved code for searching existing shows to find there indexerID and Indexer that they belong to for speed and accuracy [`b8048a7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8048a7e5748d5f27e8cf6627de5ce2d8012cef6)
- Fixed displaying of currently running searches [`c54e70e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c54e70e99b741d62cc36df1a9ec0e249a2fe983d)
- - Removed annoying alert message when failed to retrieve newsnab capabilities (categories) [`3366108`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/33661082553cd344d9da2e5aa0d4973fdca81c87)
- Moved code for marking failed download successful out of loop. [`7b54611`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b54611361c269793d12661e1ab256d0d6220b72)
- Fixed nextaired not found issues and fixed kat provider issues. [`e891e9d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e891e9d637e4c1e1375d2e12d36f08d915828911)
- Fix for hdtorrents uid issues. [`36e12a5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/36e12a5d4d0f5645cd0ff4db34c03a4709f0693b)
- Fix for torrentday uid issues. [`ddd9376`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ddd9376faf8706869fb088ff6e235b477643e1c6)
- Fixed issue with tvcache filling with duplicate data. [`9f8c49c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9f8c49ce881e452e8bb43b1b726f8a804aafed07)
- Fix for missing code in Name Parser [`688263b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/688263bd62063250a7f8dd3b88a4571961ff06e7)
- Fix for importing existing shows being set to anime when there not anime shows causing parsing errors when trying to parse episode files from disk. Please perform a mass reset of shows marking the ones that are not anime so that this issue is fixed for when it does its next show refresh. [`9e4ec2c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e4ec2cfb856b947b1707f283abdd88397a282c3)
- Fix for scene_names table does not exist errors. [`7e91d3a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7e91d3a600515c261bbdd559e3462ecf1060761b)
- Fix for missing indexer_id during migration from other forks [`886753b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/886753b76618e84019f6e33df81c80776df217d8)
- More unicode to int issues resolved [`57fabba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/57fabbad8b94c49a0eccc3220e206ba4a140e21d)
- Fixes for scene conversion and regexs [`071d51f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/071d51fcda7513744928cbc05453ce89dd4442fd)
- Fixes issues with scene converting [`96a2c04`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/96a2c047a053652a5fc2e5f441702eccbd317744)
- Fix for no status attribute error [`8d4d1a2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8d4d1a21cd30ad612b64659c83f6fef856530459)
- Fix for invalid scene release issues due to no ignore words being set causing a match on spaces, issue resolved. [`3d43c6b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3d43c6b5bf87178fe4483d2f0c6dd10aa9680e74)
- use proxies [`aae27f3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aae27f36f65c795106bf0f6bc984c1dbdc2419c4)
- Fixed issue with columns not being unique for xem_numbering table. [`b30ef51`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b30ef51b22f38d1daa44b441f6eec6fedd3a1966)
- Changed to mass action for db indexer convert code [`e255e44`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e255e44462b8f052d0bc5befe317c0ed5eba7679)
- Fixed small bug in the getUrl function for helpers. [`4b1dc8a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4b1dc8a63e3bd7f1d7bef84a48f6f5beee0804f8)
- Fixed sorting provider results by quality code, was causing a error. [`bf41ba5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bf41ba59be87bb9385bc67ece53bf51f25127a2e)
- Fix for validating episode data during provider result gathering. [`39054d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/39054d781034494aa55bd4b14a940a4bbde6feb8)
- Fix for threading schedualers and subtitles. [`0cdd1cf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0cdd1cf8137bbe670384f5c3b50ba2bf96ea2769)
- Improved name parser scoring [`e0e10dd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e0e10dd289516bf00811d7893fec222e392c3127)
- Fixed issue with facicon.ico file and static link being incorrect causing 404 errors. [`18a1681`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/18a1681a61577b3ee4c36d3b4c80069ccc39c53e)
- Fixes for db scene numbering fix [`233667c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/233667c6d14c31e583bb8b1031a9f379a5843bc2)
- Fixes interval setting for auto updates and check version, will set the interval in realtime and take effect right away. [`864af29`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/864af297c644533e219e286a56e806f8c4b9718a)
- Bugfix in failed handler [`31a63d4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/31a63d41aaadce944e5cc57e8a3bd70faf4689ee)
- Fix missing header and text in poster layout when network is none on coming episodes page. [`69a0e85`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/69a0e859abd73f6ce628a55e822943490d25ac10)
- Fix invalid responses when using sickbeard.searchtvdb api command [`16b1462`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/16b146284d7bcfc2eb923119c2464508ada01ef6)
- Improve display of progress bars. [`7dd545e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7dd545ecae4508740b63a24d27a5b94cbf7ecb12)
- Fix for migrating to new newznab provider config format [`ae5644b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ae5644ba91c36b475d46bb24f4b6368b137f4f04)
- Fixed scene exceptions issue when editing shows. [`b5e0282`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b5e02829425ae73fecaf2e11e68e21334f574fd0)
- Checks if trakt is enabled before attempting to start schedualed thread tasks. [`830a4c8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/830a4c840e504a8c0be36de155b5069108af6842)
- Forgot to commit these [`9fe6b66`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9fe6b664753d173a546a581d31d1e96ff7f414ae)
- Fixes and more fixes [`48462f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/48462f4baa8a3bf89fae47454b0a2bd15a1b9c70)
- Fixed issue with auto-indexer detection in post-processing code [`381f2e9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/381f2e9e1ab3c16e2b64aad34edc2b4087932afc)
- Fix for attribute error when no newznab responses are available [`c1a199d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c1a199d6981b7399c29bdb72c33bca9eb17c06e0)
- Fix where there may be empty values (such as cookies) in older configurations [`93f06af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/93f06af3008d53896a2839aab7d525b7bd8576d6)
- Possible fix for failed to send torrent errors [`54afca0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/54afca04725be05a73b4ab009e60cb5b146768cb)
- Fixed startup issue due to import module issues. [`efe115f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/efe115f909818420311ba5e37fc282ed05e1b892)
- Fix for scene numbering not being set properly during a mass edit [`d09f2a2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d09f2a22765ceb37be563d1c8dc6703baa7c805f)
- Fixes issue #327 [`b4627af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b4627af3d2e6fe4b9286d57314db1a88d6658693)
- Fix for new feature "first match" [`fc24efb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fc24efb957cc6995598ad5d6a1f333e19b5c414b)
- Update .travis.yml [`90bf7b8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90bf7b8f3b2dc9a19f3cbef94dd87c35b0c75a47)
- Update .travis.yml [`ca42757`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ca42757ed450c47b7ace11e78489a21c12b13efb)
- Fix for No episode number found error for air-by-date/sports shows [`0fddbac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0fddbac1c4da642a016000a4a312ea00ecab2ec9)
- Fixes issues with inital setting of branch version on startup first run [`326d020`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/326d0204c0c437cce66c815f92ef9722ad716d81)
- Fix for sports shows. [`f340f9b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f340f9b073c701b52eabcdd86b8f1f07b35a1f90)
- Fixed name parsing result issues with improper regex patterns being used. [`c4a0f31`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c4a0f314fdfe5b750c0d8314cf9912b8688e43ef)
- Fixed urls [`c9abdfb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c9abdfbac23d3ff2b3804b48083f25f9962d5d0d)
- Fixed naming issues and parsing issues. [`4e83cbe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4e83cbe6d13fd222e399bcdbd87152c241ec028e)
- Change code for returning highest scoring match to use generator to avoid overhead of sorting the list [`2da18e6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2da18e65ca6faed2ded235922a81a60e8f6d516d)
- Fix for #390, add flag to use proxy settings [`36359b1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/36359b1547f5d3d94fc46e187310ad59dc1629f9)
- Fix for web passing variables in a format that is other then expected [`49027d6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/49027d6185ed40b49ab8f5fa20218bb81bef57a8)
- Fixed indent properly [`0afdb79`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0afdb799e61f0f4b31f5919f92b39dd005392ece)
- Fixed indent [`803d560`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/803d5601cd3fead4133b23d0be83247ca63efe57)
- Fix for air-by-date shows [`896295b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/896295b090c1fdf548158f2ca5afae207d906189)
- Reverted changes to default.css, was just to widescreen for my liking. [`4a0acde`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4a0acde729a5c95e77ce6e76be7c3116c040d597)
- layout fixes in for home and displayshow [`0790346`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/07903463e39ca13e7a12ad3f66ce4793dadf2d01)
- use tor for generic providers:w [`65e0dd9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/65e0dd9ff7c73f8fee0c0ee08b708635a4585064)
- Fixed scene numbering, was not being converted to a int before. [`5b69783`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5b69783e86cced47d40829ae8caa381138da3417)
- Improvements to PublicHD provider code [`049282c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/049282ccb9b73ae9b0f83ee09ff62724427030f7)
- Fixed bug with air dates being malformed [`b3662cf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b3662cfb7b79668b906ca918cc5adf27b9564223)
- Failed processing backwards compatibility for original param name "dirName" that has been relabled to "dir" [`a165b89`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a165b891e998a31672caa9335885bcfa1a1aad59)
- bugfix in tv.py [`ff548a7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ff548a7f6bdf655fd55740bf740b24c26f805ee3)
- Update scene_helpers_tests.py [`6270f25`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6270f25176768fbc8512aea59df30baa4d526e8e)
- Update scene_helpers_tests.py [`b7381b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b7381b3d0a44039f1bbd562b533a8db63b33eeb4)
- Possible fix for failed to send torrent errors [`6c15943`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6c15943363fc6eec5593166af4550bbdd04e5ebf)
- Possible fix for failed to send torrent errors [`8415b32`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8415b32fc6f3f2679989485dd19ea929ce2fffe3)
- Fix for images in cache folder being deleted by cleaner routine. [`4801990`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/480199085e980413c7eb1302df802ed7ea3f6275)
- Possible fix for stacked provider names during backlog search. [`6957bd0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6957bd0656813a7d0fd3534a908223962d446d1e)
- Fixed redirect issues which should now resolve reverse proxy web_root issues as well. [`9e36531`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9e365310b68a8de3a4095ed4c75e3adac2a5298a)
- PEP8 Cleanups [`c3a1381`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c3a13814f19b89c52446936e9677c72340c10654)
- Moved scene conversion routine in Name Parser to end so that it only converts the best result match and not every single one wasting time and cycles. [`7defffb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7defffb4f11253b0c7131dedc810d8437eabf1c3)
- Fix for custom scene numbering, now able to correct numbering or remove it. [`4c9da4f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4c9da4f44807b32ef059bef91c16e55c13bcbd1d)
- fix for recent sql errors around connection object [`8fbd915`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8fbd9155d37acf1b449a0769967b98306d57ce66)
- Fixes issues in tvcache [`75c7fbf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/75c7fbf137f32e2a3d12943baa436a0b5354fe6d)
- Fixes issue #30 [`8c78b55`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8c78b558b52a8abe8490225949abffce98a871aa)
- Fix in indexer conversion code for mainDB [`5709c88`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5709c8843c7f0b5e2cb24209839a82d813a3f5f8)
- Fixed scene naming tests [`1a37238`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1a37238ba649cafd512443f407cc0c117e67d9b3)
- Update .travis.yml [`93f56ad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/93f56adc7eaddba5898832c515502ddeb8c7c168)
- Update .travis.yml [`d424920`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d42492017ed8762b4de0b0aa6e6b6ed3548daa52)
- Fixes crash on general settings page when git output is none [`d5daa14`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d5daa14dc0463e53964461e16a8bcd60f12e5a50)
- Fix for active and status sorting [`f4e351a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f4e351a1603fb151d74983f7c0801c14686b49ff)
- Not skipping when self.status = None, but assigning empty string '' [`32a88cf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/32a88cf105119130286b172925735ac4f1bd0491)
- Fix for no attr success [`b0d550b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0d550b3fbb58ecdee6ae3733d4ab593de13ca96)
- Reverted backlog search nextrun changes [`9eec99c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9eec99cd14e4dceb59df2e1338b4b7a33db6a38d)
- Fix for version attribute error [`4fdbb24`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4fdbb245878b86ce3144a9920eea2aa172ab5a28)
- More fixes for source code updating [`1bf4790`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1bf47900dfbcd2f626b346892118c322a3d6de77)
- Further corrections for torrent download issues related to content being empty and not properly checked in advance. [`6e6ae5b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6e6ae5bb8737ada062abf726311862be9dd0bccf)
- Fix saving rootDirs (refresh before save) [`b63dffa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b63dffa3a0878a00f0ad43d33400e63fba569c0e)
- Provider results get sorted by quality before filtering occures. [`d6442e0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d6442e06850ba03b4c506eece893dd0a4cda6ce2)
- PEP8 Fix for backlog searches [`8b5559b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8b5559bdef73e31ce0e34f3c884e1ae69f54b5fa)
- Reverting previous changes [`18d7884`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/18d7884c2d007ce14d5663fb21f42d44181b6470)
- Fix for DB issues on new installs relating to database version checks. [`0599a89`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0599a89565dcfc3ef433fea6e0f836456db36f4f)
- Fix for force update. [`c9f8001`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c9f800128ef8e22c840b6c131b075d9c4cc63376)
- Fix for invalid literal for int [`6295d6b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6295d6be94e56fd7816e7e8617b1a9ebb6f2577e)
- Fixes more non-sense issues [`580afec`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/580afec2a791e1edd72b9ee959490ea63133be17)
- Fixed unicode issues [`1c56876`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1c56876ecc976f25c82b8ecc3f210065381c3cb0)
- Indent fixes [`dad75ae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dad75ae09b5f913dcea8dbc89dcd13b2c93464fc)
- Fix for published_parsed errors [`dfd8ead`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dfd8ead9f858b29627f4c5c7dff861e12c785e11)
- Fix for showObj attribute error in cache [`1f74488`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1f74488a38d016f4cdd5a0a1270426d6bda214f0)
- Fixes issue with proxy setting and config not saving. [`6d3f66a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6d3f66aa4d8e807f7c4b5c1647944e1fd6422eb0)
- Update utorrent.py [`6c84fed`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6c84fed53674344f8e1220adee58b4a898b017ad)
- Fixed bug "Unknown process method" in postProcessor [`bd84656`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bd84656517c34a215f40e016aa7be29f9c7e2c95)
- Fixed couple bugs in cache control [`9124c52`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9124c528a8972468ee39ada0ea1520c081b53cb2)
- Fix dropdown confirm dialogs [`8d12cad`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8d12cadd14ec21ae0087e9a4e5d67bfad377a50c)
- Possible fix for failed to send torrent errors [`f307317`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f3073174eda66863daf7d467ef4621a3728ffb81)
- Changed js code for checkout button to perform a windows.location.href to redirect on click event. [`27c4b66`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/27c4b66bf6015a8cded769de0abc67f668f0a834)
- Provider DB connections remain open instead of constantly open/close for misc db calls. [`423c09f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/423c09fd9edb9c64a0fc572bc4d781b2c00a8449)
- Fix for nameparser error during PP [`14fd0da`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/14fd0daa6c6c1249fbb3299be2203fa43a8437ec)
- Memory cleanup in sql db routines for mass actions. [`b19aafb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b19aafb807703db24f20ca35357bba562cf8fc00)
- Fix for basicauth and no user/pass set [`4513525`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4513525cc406b0f46e25708db6856e93146c0a26)
- Update network_timezones.py [`4c5425f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4c5425f4d1e444ede262503896916d652989260c)
- Fix for import issue with episodeCache [`3d062b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3d062b35105ef32dcb471105e9fc9791f72ea53d)
- Only walk lists if they are populated. [`e475d2a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e475d2a22d94a97576bf3743f324c7c2bc771cc2)
- fix for issues #321 and 258 [`16441c0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/16441c05824ebc4319b349127c5d14f931d82de3)
- Fix for post-processing issue of not being enough info [`b6f7753`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b6f7753ec746137ff94a425d2c165c77b37b200c)
- Fix for issue #255, metadata saving for xbmc12+ [`880e923`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/880e9237149e46fe5a6bbe56b1f4efdf3544c1f8)
- Updated regex patterns to accommodate sports shows with dates in them. [`e30ed48`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e30ed48fcfbb32427a4427f54c6a88e2b276b42b)
- Revert "Fixed up regex patterns for better matching of sports events" [`67b7eac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/67b7eac21b929ad4e00310c09a0c06961c50f64c)
- Fixed up regex patterns for better matching of sports events [`8ee4770`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8ee477085eb282cc1936037ff1460bcd29015da1)
- Now returns both tvdbid and indexerid for 'future', 'history', 'sb.searchtvdb' and 'shows' [`5abd9b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5abd9b2f97996774756883a64ce344c1c5f93f14)
- remove duplicate variable [`09b106e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/09b106ec6b5a9f312dba215aa53c0736ccd09c57)
- Regex fixes to resolve issue #10 [`9ba772b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9ba772ba44348623486369a8128688f94ad826a8)
- Update generic.py [`11f9a89`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/11f9a891f0d1dbf7fa5f444e1a67a80f2c65636b)
- Fixed scene naming tests [`be0e3ab`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/be0e3ab83666c86f29eb22fc22e1919f117084b7)
- Existing shows no longer display when adding new trending shows. [`a5c0fe1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a5c0fe1d3c76be3cadae56e0a933bdbfefc79d17)
- Fix post processing when using tvrage indexer and mediabrowser metadata generation [`687d2b9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/687d2b96abe2016a910d04decb4934ba8150b940)
- Update changelog [`3ffb561`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3ffb561282f6478f9321aa0e127dc207297dd826)
- Fixes and additions to testRename.tmpl [`3c1043f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c1043f77ebaf5fad2b4ac19abf1dfe10b8124ca)
- Fixes displayshow error for series with special characters [`d8e52f2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d8e52f209884703f4c4ef04280f97b69679d6f67)
- Fixes issues with newznab providers [`905b41c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/905b41c46a22d52701615a06fcf68c4f021d9a55)
- Possible fix for failed to send torrent errors [`4752e07`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4752e07733b7969b3a3563d68ab1e2c82b980d6d)
- Fix for version branch issues. [`ad39ac8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ad39ac87728d9b03a07564741c60f2a02fcb2f52)
- Fixed cannot find 'capitalize' while searching for 'capitalize' error. [`7b187c3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7b187c3add63e47a8fea4b488b08116e37e7058f)
- Fix for renaming non-anime shows and absolute numberings being applied by mistake. [`39d9fc6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/39d9fc64346b4e0781c5070d8bd3af7309fb73ab)
- Using unicode for name keys now in NameParser cache, resolves 8-byte error. [`89c8ed4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/89c8ed437286fa48437e5751f60979ef5dfc3151)
- Fix for startup issues [`1b045d2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1b045d21948cce661db283f12c0facb860da98c2)
- Fixed robots.txt method. [`508c094`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/508c094f484011517fdc8adaeffe04a5c9d123fb)
- Reverted previous changes made to regexes as no longer needed and started to cause false matches for h264 as a season and episode number result. [`9d8f695`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9d8f695e5ab7a88fad7d971a9493749b53db3075)
- Fix for release results x264 issue [`cec0140`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cec01405d84ec196a942a1039923653c3c95d7d3)
- Fix for tornado redirect function, was not properly returning. [`3c370fc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c370fc5c9d348c7b37cf9f83c3b3562c62caa71)
- Bugfix - fix issue with Pushover test notifications, false-positive if api/user keys removed in UI but not yet saved [`e50ce50`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e50ce507e50126086aa229ef762efa1fcf52e838)
- Reverted episode cache changes [`c2ba2d6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c2ba2d6550df58e8008de634a0f96f7ab2eb249a)
- Fix for invalid literal for int() with base 10: 'NULL' [`4784b46`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4784b4619f18c38a630b6c65a549e95553319f33)
- Fix for nonetype issues during parsing [`a9f1421`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a9f142184abdbef0c3b75efb15e00b9660f0b14c)
- Use day numbers instead of text for language independent day name fuzzyness. [`02ecb18`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/02ecb18effddc15f2f90652f8778f8bb32bddcf4)
- Updated readme again [`bcbdf77`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bcbdf77bcba4855d30c2644e1a5a9ea1ac97466e)
- Correcting typos in prefer_season_download feature [`fde5ce4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fde5ce4c58576be22ea9727efe84a4ba04fab67c)
- Fixes sql issues [`72828e1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/72828e1a8dd76537bf81a02022a965650946176b)
- Fixed inital scene numbering database check to look for a value of -1 before updating to insure this record gets done at startup once and once only [`c2e79bf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c2e79bf0319d055a7b4d65c31a40b34114237fc5)
- Fix for issues getting indexerID during cache updates [`dbee4b6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/dbee4b6dbf58862925be9fe55640702b75130b2f)
- Fix for new shows [`12ca73b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/12ca73bb0e851a98bf5fdfc2a08ed5eac60b7af8)
- remove default proxy setting, fix indent [`ddaa5bb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ddaa5bb5e671f18aaa9bc403275106c507eb4bf9)
- Fixes issue #53, ignore words not working correctly [`9171a28`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9171a28f68e2bc635d50fa3e6f889483004740f9)
- More testing for auto-updater code [`3c215d8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c215d8cdedd3b4ec7b76664453750a52bdb3fcb)
- Fix for curRegex called before assignment issue that was pointed out to us. [`a65e688`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a65e68837c3ac58138611c88a29725da282a25e4)
- Fix progress sort direction for poster layout view on home page [`9cfad22`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9cfad22870cea5209fb4067f4026a78833ec1ae6)
- Fix missing kat url in config_providers [`c0d6641`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c0d6641f048238a618e525297384f4332b60f2b4)
- Make hardlink debug error more verbose [`560ffca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/560ffca7dd46a6799c05d438fb6c1d6ae1324d28)
- Fixes calendar always being unprotected [`c8d5989`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c8d5989676fa5a032baec63f5a41e6523bd17fb1)
- Fixed backlog frequency calculator code for realtime changes [`47eb4fd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/47eb4fd21a0902402fb56042a2747b90e8ed3299)
- PEP8 correction for search web html template [`640b840`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/640b840cdefeb0ff7672acf8cbf2f75b68ccd17f)
- Provider image fixes. [`b5c703c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b5c703c8934913cecd74462ceed02e95a90a7ee8)
- Fixed ajax calls to update function. [`1908f76`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1908f76eaf198c52c85e8b0db04b77e03f971d76)
- Fix for absolute numbering issue during renaming of files for non-anime shows. [`5fb3fe6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5fb3fe67974c8394384700de7b4e780c5e1fd3be)
- Fix for show parsing errors to be displayed via debug logs now instead as a warning. [`0e3495d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0e3495d30f031e99da7b22994b217a6a12e761c8)
- Fix for displayshows error: ValueError: invalid literal for int() with base 10: '' [`8063ac5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8063ac5d7a374f305e57c15c78948884df384462)
- Updated regex for show series name matching, faster matching. [`f16ee09`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f16ee09501b650b6ed04f30da594baa45ee927db)
- Fixed ImportError: cannot import name OrderedDict [`7d2f7c8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7d2f7c82330f57e1da00006d7bda06f1e23b4473)
- Fix for searches of anime shows with absolute numbering [`ba2a44b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ba2a44b1d1e74b0584719964a12e3539f5ce63fa)
- Fix for mass add and existing shows adding [`775730c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/775730c3adb5e9597704dabd3b28802e9b27724b)
- Fix for issue of downloading multiples of the same episode [`7ca19b8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7ca19b88d69b0362af862a2825035daa1c14945c)
- Fixes issue #325 [`6ee60d2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6ee60d213a663918b0ec7f2981407f108e309796)
- Fix for showobj none type [`e379d57`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e379d57376bf297690d2fe801be059aaf141b042)
- More XEM scene tests [`5d16eda`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5d16eda62026afa23532269fe38aeaa7aeedb94b)
- Resolves issues with saving notification settings and http(s) setting [`2b57fce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2b57fce5e6bd4dd460009b0349e9e6fc1a51a637)
- Fixes issue with previous db migrations that failed and left behind tables that should have been dropped. [`bc79c93`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bc79c930185ebfe5a7a3b55f98bd20eaa41f0a32)
- Removes primary keys and unique keys from xem_numbering table in cache.db [`e7cf923`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e7cf923cc03c42a982f09cd75c337ea4068dcb3c)
- Fixes issue #27 [`ea38289`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ea38289dd83b77c596d3dbeb26075075abdefb19)
- Fixed bug #897, switched message to be classified as a warning instead of a error [`b829502`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8295024befcc605c0e95e8977dea63eb7c8010d)
- Updated readme [`5eaa84f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5eaa84f42922fb5e84a17b635b0f2fab756ce0e3)
- Update growl.py with missing registration of update notification [`e58f3fd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e58f3fd9cd11c9537be0328ea334bdf2f890d6c0)
- Change: reduce width on comingEpisodes Calendar view for new page width. [`46554c3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/46554c382ea51b462ccdc5a4102d6c6e548641c8)
- broke the arrows woops [`5e5f967`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5e5f96722e7f0d81e1c2eaab6a284fa6c70cfc92)
- Fix anime naming patterns being stored as sports naming patterns [`b83b872`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b83b8721a03a416120f57f63b26aaf7bac6482f3)
- Fix another unittest error [`5a5b2af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5a5b2af676eb4eb4e99cd1a9882779a144561494)
- Fix backlog nextrun to return datetime instead of just date [`41dbbba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/41dbbbaa9bdf08fe42c45a2772a0ab1628f97be1)
- Fixing more newznab issues sigh [`b43248a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b43248a6446269e1baf0ff62e1a7b570e6bb2b59)
- Fixing typo in last commit [`981d661`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/981d6612b8cf527c11dc31b27132a762110767ee)
- Fixed issues with cache results being used during searches [`8f6d014`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8f6d0148307d1ba1b0bfcda43c55156725a28566)
- Fixed search issues regarding error about result attribute being referenced early [`2193a4b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2193a4bfd1e5ad9826f4c6ddffae0fcf2f9df46d)
- Code fix [`3ae4c13`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3ae4c13104e489a0d68bdffa38de1be917a732c0)
- Fix for brnch checkouts from webui. [`4ff4ebb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4ff4ebb0d6bad8f2beeb86e46085b0b91f77d778)
- Fixed a typo [`331be09`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/331be097cb3a84a4bef65b38fa332256d14a9791)
- removed sleep timers from db code all together, overall speed increased. [`6e61314`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/6e613145b32e3eb0a21df7e01f431990b0e380b6)
- Fix for rls words [`cf99eb9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cf99eb962559cd52cb06f00449c402f3c29eae08)
- Fix for anime showObj regex matching. [`9dd679e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9dd679e30f886465644e6b91275c7c2e253f449b)
- Fix for metadata mede8er provider for error: tvdb_attributenotfound: Cannot find attribute '_actors' [`561a12a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/561a12a735fb3623c37f8bc030f05160c0a2f1a0)
- Finally thanks to the new error handlers we have resolved the dredded issue 500 errors, enjoy! [`2b0b0dd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2b0b0dd885a751a8780a821f57735730c77c1592)
- fixed broken images when changing from default (empty) [`c5949b4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c5949b4672334c4981d4b337d2d7d8c63a23858b)
- Fix for edit shows and add shows. [`93e2e93`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/93e2e93b630fa977f32272c07382ec1ea44489b5)
- Fixed minor regex mistake in code. [`fcd54c9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fcd54c93d6a6482f0e0f8daeea964ee4f7b45f1b)
- Fix for anime regex's 'anime_and_normal' pattern, resolves issues with show-queue refreshes [`a2a44ea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a2a44eae85fe5729549ee5e9f4ad5fe2ea41b55a)
- Fix for PID file: /tmp/sickbeard.pid already exists during auto updates [`95e928b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/95e928bfcbdc39ac6695d36a8fcfecee54194945)
- Fix for showPoster() api calls [`bd582d1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bd582d18d0d7ddb174e1f20aee765bb5315bab09)
- Fixed issue of forbidden error [`29c5c4d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/29c5c4de4d9be73f64320d0c1447574c7f83038d)
- Fixed searching for new anime shows, unicode issues resolved and Naruto does indeed work! [`d07976f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d07976f05721fc1d27aaa6bd66caa817cb70a6b3)
- MainDB is backed up before being restored now to .r* versioned backup backups [`34009bb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/34009bb9b877ada1e057095d111a98733dce30d0)
- Fix for sql rowcount error [`f052848`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f052848e52c19b8384c56aec2a9b2ebe04df967d)
- Fixes originally aired dates and times issues. Please perform a mass update of all shows after updating to this new commit to have changes take affect. [`8ac0b79`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8ac0b799862ec323d96fd427434b8f01d4886f76)
- Fix for UnboundLocalError: local variable 'rating_text' referenced before assignment [`d42b864`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d42b864ecc254d0f5ff30ad0cad42ff1ac2d67b5)
- Boxcar2 Notifications now working [`704281a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/704281ab589cc60972f2c0f4a4468c3a696f1c44)
- Fix for adding existing shows. [`e6056c5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e6056c57450722f4a326790da4f5c8f0b0f528a1)
- fixed post-processing uncaught exception [`4cd67aa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4cd67aa6ec53262c612abd0fc5ba849f594c7869)
- Making the links to submit issues actually work :) [`d4ad2e7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d4ad2e7fb75af73305f85c2ef746f36a6f7b147f)
- Fixed missing code. [`0871435`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/08714357ddee1c51712ef5a313df5192318c6d6e)
- Regex fixes [`50b792d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/50b792d6df92cda9cbc3eabae3e848093b4a3484)
- Fix for None type in cache [`e10a725`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e10a725d276c1bb85cf759f5ffb83813919c186b)
- Fixing typo [`5515521`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/55155214c1712d04a74d1dac6467575f988d60e5)
- Code fix typo [`8c2c319`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8c2c319c7fdda040d3104467c65595c53ef0f2ba)
- Fix for update frequency ... again! [`1cfe91e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1cfe91eb805e18f76e93631dc85bb8abdf26e9cc)
- Fix for shows that are air-by-date [`0ae27fa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0ae27fa6e6dd9b2162919c7c4fabdb4151c6cce9)
- Update __init__.py [`5d9c84a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5d9c84a15ed996c9e92c5ce594e3dcacb30b038a)
- Update scc.py [`90620e4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/90620e47b88ef52aaa6a64dae21588c54de03bee)
- Fix for rss torrent feeds, resolves issue #32 [`77696ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/77696cad66c91982d238965858228cfb4028f3ec)
- Fixed a typo issue [`4caf244`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4caf2441d616a8b48d3013c70c8d2747b20cf33d)
- Fixed issue #20 [`fb85c6e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fb85c6e50e3e53bcd891bafbf0f9851b5d36d012)
- Fix for regex pattern to match Month's using more then 3 for there abbrv [`02ef367`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/02ef36758377d8b914e3422e731da3435cc8d7c9)
- couple small bugfixes in code when it was expecting a string but got a integer instead well trying to create a search string for providers to use. [`146d9ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/146d9ba23b11fa0aa98841245f7aa6d813d18892)
- fix_checkdates_in_the_future (itofzo) [`3e3e6d9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3e3e6d961d3d8415c484c22d1f2d4695ba0b9f46)
- Bugfix in parser [`a4b11a0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a4b11a0c95472ae7948936fe413d3eed3ff6502b)
- Post processing bug fixed, forgot to set out indexer api parms after correctly setting the indexer based on values from DB when performing automatic post processing lookups [`fddee6d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fddee6d687785252c451b887c12f42786d0c696c)
- More bugfixes for post processing code [`d282f76`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d282f76052516f4c18995d60e58963d0f3dbcea3)
- Update .travis.yml [`47c7420`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/47c7420581a7e639da10933956af283a6a646748)
- Update .travis.yml [`4d96b01`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4d96b01f028d4db63662f74ef02d5f16433acc64)
- Change reporting failed network_timezones.txt updates from an error to a warning. [`afce91f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/afce91f79de9bc09a97e3ca3520e2819efcc8cca)
- Fixes unicode issues during searches on newznab providers when rid mapping occurs [`e63ffd3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e63ffd363cc4e566313c441088b4d36a285258c0)
- Clarify description for backlog searches option on provider settings page [`195277f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/195277f708a4272ff39cc3094f82e387be4adb1c)
- Fixes show folder not deleting if files remain in folder [`4adad57`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4adad577c8133fd636912b83146b0121da142559)
- Fixed saving general settings rootDir error [`610d1af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/610d1af4f0e08e3b9a68419dcaa98b7670f72bbf)
- Fixed saving general settings rootDir error [`a0ef748`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a0ef748f3b2d00342ed5759cb2d9a9db6ed1bdc1)
- Changed log message to be less confusing for torrents [`0a936ea`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0a936ea1ef6932b5301505c8fe3ea1a573e6e00a)
- Fixed code to set branch version at startup [`bd2748d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bd2748d33aba2137848c99e8ef184e59341a9200)
- Disabled purging of feed-cache items for providers. [`cc07bdb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cc07bdb12f0ebfc7904a4a51e88c12de0c09cce1)
- Possible fix for error 500 in web gui when trying to get a show poster and showList is not yet been init'd [`8045976`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8045976c1519a2e54e898d737cdcc2b9d6568db4)
- Fix for rss feeds clearcache [`7bff5a2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7bff5a246f6823aaf01c63e9215928c925c9d022)
- Code cleanup [`550e671`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/550e67135efe342e85f711c2473363c7c5012a4a)
- Deletes duplicates found in tv provider cache before creating unique index for provider table or just performs cleanup of any duplicate record period. [`13cbffb`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/13cbffb6d485828e73359df9def28a79176faa04)
- Fix for manual updates when auto-upate option is enabled. [`12ee35a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/12ee35a5e6c3f216b2334db5f1046145da76d1d3)
- Fix for failed download handling and sql issues [`2eec706`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2eec706197c5482e6204df236f4ace9b7a177233)
- Fix for autoreload issues [`09297b8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/09297b853b4c18fff1dc4f451e26047de71d0744)
- PublicHD removed till further notice. [`4df31bc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4df31bcceeff034f151fe3160ba2b740d04a75bd)
- Limiting search to English-translated only (for now) [`0e989fe`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0e989fe90fa7d00863e84297eed72da14ea140e0)
- Fixing error in findpropers when air-by-date search is attempted, but show is not air-by-date [`d1d9025`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d1d902597158e7c39149573615845e97e70aadf5)
- Fixes issue #337 [`bb4ef18`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bb4ef18fe3921bf1414174f95d7675506bb3533f)
- Fixed up sports regex matching pattern [`42b11cd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/42b11cd00015be6ab228d2b4ba8d74d571d14936)
- Fix for mediabrowser absolute_number issue [`b9fa92e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b9fa92e439bad6eae65b7206f36a948cdc0c929f)
- Fix for thread locking issues [`bf31077`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bf31077cc295f8ed39feb3187642311718a6971a)
- Fixed issue with searches that contain special characters such as () [`aa94711`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aa94711788f3a74ea39aeb89b8d9d37cc63c9deb)
- Bugfix for sports regex matching [`e62250d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e62250d63b3d0f6d590b0796f484382bef7c39ea)
- Fix for bug #898, fixes issues with show image overlay when using small poster layout [`aa76734`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/aa76734f56c1b0f2f23cfd0f0432a5aac3969b52)
- Revert: Fixed regex issue (3e958ca0e1a517f542b130709a0859956811e737) [`9257a5f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9257a5f2febe5f5298dbc2b738e69ce615fd72bc)
- Fixed regex issue [`297e690`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/297e69094aa3e1c0e236b446f6d53d1ec86d5555)
- Fixed regex issue [`3e958ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3e958ca0e1a517f542b130709a0859956811e737)
- Fix typo breaking layout on comingeps [`d9c76b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d9c76b2f53569421fb91308eef7cf268be99189f)
- Fix exception raised when converting 12pm to 24hr format, also handles 12am. [`d6950bc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d6950bc6f140884335dfcd5d92ea0b076d978d7a)
- add subtitle to cmd show and shows [`f185c1f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f185c1fee0e96b70667a635af041248ca21f3a5b)
- fix not loading proxy_indexers config [`ea3a165`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ea3a16598794f7031eac8aea8524486eb22efc64)
- Change: reduce details width on display show page for new page width. [`7bff816`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7bff81694729435b49f074e50ac9e74875b51b88)
- Make failed torrent log message more verbose [`16a54e6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/16a54e62d6ee2fce6883ae8ab4bddaa79fece6c0)
- Fix for custom newznab providers with leading integer in name [`c26eb39`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c26eb396957ec09be592ce4ea86d9cd5f4ef0fda)
- Removed unneeded code from theme_name tests yesterday [`db6eb33`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/db6eb33db4770da6cff641560ea08f75c5569c8f)
- Fix omgwtfnzb provider retention = 1 bug [`a72779d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a72779d5d31147f1d31e51f5819a11efd28d5ca2)
- Update testRename.tmpl [`ea8d109`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ea8d10902907e61cd3f3727ce1447c7ec7d2d7c0)
- fix for fuzzydates on comingepisodes list [`060fa65`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/060fa6562d35e867c7d0b96624444a7da10f5e66)
- Fixes shows not being added from tvrage [`3c9f1d7`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c9f1d754d52673434278b46eba5287f493cbdd3)
- Fixed the qualityparsing for nyaatorrent search results [`7e3b984`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/7e3b9848bd87a58b93d5a9273f832ebfed758d62)
- When no absolute episode number retrieved, fall backto the scene_episode. Else search will be done for episode: 00 [`4b1b3c6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4b1b3c6488d68cb73b4d535a561bace7447ee847)
- Fixed typo in searchBacklog. Introduced with search from delta functionality. [`47cd8b5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/47cd8b53f0d83ae72c0b4996c9a1eb76d5243d64)
- Can't += dicts. Need to dict.copy() [`4bfb271`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4bfb271e8d447c2aad5b42cdbcbb37c3dc95f62f)
- Fixed unicode error [`f5a6d45`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f5a6d45d8f8cecb3ee5884e8eba5bdb0a38961e8)
- Bottom of page backlog nextrun shows time as well as date now [`4a03885`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4a03885956551cd62f1f9c5d711674670e7a6a5b)
- Renamed filename for donate button [`e3db9b8`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e3db9b8c93ef75d3b58cca66b73c4e87db9e7a00)
- Possible fix for high CPU usage when doing NZB searches [`4fe3a96`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4fe3a9605165addf4b6602712991a1836081a883)
- Fixed newznab to search no more then 1000 results [`991a939`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/991a93991e515630e75d82b723aa711e98f1bd43)
- Possible fix for incorrect show matches [`b03ffa2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b03ffa231d26990af685acd6c20dac80631e84aa)
- Fixes typo in previous commit [`ba5e547`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ba5e5478e02b83045348ca5a83a495c4d8a00c70)
- varable [`e02490e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e02490ee26afcbca8f195a0dca85dabefbebed19)
- Fix for season pack searches [`e2d1178`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e2d11785150f65b30855971ba69a76f49d3684d4)
- Code fix for attribute error [`9714fc3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9714fc3299774e013fec3c74c12b701d653ecd61)
- Code correction [`50b91f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/50b91f9d7ceae7b3ba0b7b8cdd609235e54ccc1d)
- Code typo fixed [`f1c45a5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f1c45a596dd22878ef06b5f5f0698ed0f160a9cf)
- Minor code correction. [`f5725f4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f5725f44022d87d17d1a2c15434d8855d444127c)
- Fixed improper line indentation [`1790653`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/17906539ae037c04b9840114ed07669f6201791d)
- Fixed notifier failing when it shouldn't [`ff9c8ae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ff9c8ae82cf797cc0887de266b841d79f8472703)
- Fixed a small typo in versionChecker [`b4efb2d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b4efb2d641b0649618176c30b3dcd792849221cb)
- More fixes for webui branch checkout feature. [`e9eca83`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e9eca837a899d79859712a5c30c2310950adfb4c)
- Fixed code that was preventing branch checkouts from working. [`ef8b4e5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ef8b4e587dd63c7568d8d0938b27aa90ef19d248)
- PEP8 Cleanups [`fcded3c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fcded3c3cf474b7e28371cf84aa748e77ee3358a)
- Fixed issue with appending UNNOWN qualities to provider results after being sorted. [`899d03b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/899d03b5feb3184c6e58ad7173126166a76f6cbf)
- Fix for naming pattern issues. [`5802fc3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5802fc372cf42782a163ed3aab020dc306a66bbe)
- Removed a sleep timer [`3fd5f75`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3fd5f75180ddf4f9d14d563852cbe2713ab47ade)
- Fix for XBMC notifier [`c7e58ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c7e58cadb547593a3bebd0591cb4107a3e39b6e7)
- NextEpisode sets episodes that dont return a next air date to todays date to help improve load times for home page. [`23239e0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/23239e0a5d7b112c939f781d15f65c7a3f3b679a)
- Fixed video root issues for video player [`3eab864`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3eab86478a1d22df34a72d11fcec9c23ac324338)
- Fix for api builder. [`2e8c8a2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2e8c8a262fab094108459b152b9180b88b6fa658)
- Fix for uncaught exception error for 404 errors [`06e99ce`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/06e99ce4a76bfe046abb2877469d6f9eb9113235)
- Corrected self.finish to self.write [`145433e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/145433e19a994a617cf379ba4f48600c717153a6)
- Fix for H.264 issues related to regexes and matching for parsing release names. [`858951d`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/858951d31c511b02636e670e5d8b0107515c8289)
- Fix for restarts/updates issues when running as a daemon. [`39f32b3`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/39f32b3b7cd9edb09d9597571c34c8f66434b456)
- Fixed issue with backup/resotre config file variable [`696a1a9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/696a1a9f4af2e6c82afa6e12f2ca377e6b16bc82)
- Fix so that scene converting does not happening when performing naming pattern routines. [`b0149cc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b0149cc65df8a8091f9f51d1729c2e875a2f9747)
- fix for tornado error handler [`bbbc746`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bbbc7469fbaba6942b075c544967c11759c6441f)
- Fixed version string [`faa6ca5`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/faa6ca5103d279710f03e76392260addd826c372)
- Fix for mass edit [`4443a5a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4443a5a6497af9f8edf4b08a18d577ee6e00e138)
- Fixed basic auth realm issue, needed to be quoted. [`e202cbc`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e202cbc0ac18aea37f74b17369aee5f90c840439)
- Fix for scene exception update error, please delete cache.db file for this to fix tow take affect. [`067438b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/067438b5d91a6a99eb818da227795ee8527c9176)
- Fixed branch version to reflect proper branch [`1eb5fe4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1eb5fe4fafb05c082c95c97c672ec9bbf4209a2e)
- Fixed for adding new shows [`a742c27`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a742c27f09ce487cabba85ad0c5bad1f0eced563)
- Update tv.py [`3384e2c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3384e2c51d2f7ec8caeb715eb37da1e814ff10ba)
- Fix typo in last commit [`8f3469c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/8f3469cce7d610022453b88846cdea9c164be91b)
- Removed unrequired extra sql transaction append line. [`37fceb2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/37fceb2704629c5c6355d0d50a53414bd57c2613)
- No need to convert from absolute numbers to season/episode numbers twice, fixed! [`4f32ed2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4f32ed262c4c9f955408f5deb7b8b05c4174a2a9)
- Fix for show opt not in __init__ issues [`0ddcc3b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/0ddcc3b58a65c302d30fde8d0abd754d54bb0986)
- Fixed issue #473 [`bc05a9f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bc05a9f6fad2ab77f38c7877879c992260566c56)
- don't use proxy by default [`348c0ed`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/348c0edf261c1120a0504c3b0a294c18c587f257)
- Fixes issue #423 [`a0bd46c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a0bd46c18a6000c188dca55194361433c7265536)
- Fixes issue #374 [`afdbc44`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/afdbc44a4790fcda0af881071b2a886b94dc76f2)
- Fixing typo [`fca48bf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fca48bfe6457d9d1eb7213f813653117120543c8)
- Deluge likes a username as well. Updating UI to show it. [`33751b2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/33751b2c6182b689c8d552896fec9144ff17821f)
- Fix for airdate issues during proper search [`b59c8fd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b59c8fd1ec13bd6a53a498eaf240177b23f46580)
- Fix for rssfeed [`99da474`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/99da47464dcb85d26125a6a861de3b8c3eea29cb)
- Update db.py [`2079863`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/20798639ae86b580c27e0b95fbc5a93d59e5778b)
- Had a few requests for this so here it is. [`88f7ef2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/88f7ef2c93c1da4b777c99489d0cf8fb2d759d71)
- Fixed issue with saving show info to DB [`a47136e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a47136e551a3df4366a7794f797e27e8d793bcfe)
- Missed one :P [`ac65eab`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ac65eab3c062c902553d9b46cc81b7549be4558f)
- Fix for indexer being sent as unicode when its supposed to me integer [`cecd35b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cecd35bb5d9a6029ef63b265a9d6122578f6d291)
- Only log deletion when we're really deleting [`a843303`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a843303812e940ded5788d4cd99e5a89b16af053)
- Fixed typo causing addexisting shows page to not function correctly [`deb355e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/deb355ef88c7f62b472210790e5fa4d983ee1e91)
- Fix for issue #291 [`74c6bec`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/74c6bec150190cb92b479e58602797ed9500a550)
- Changing sorting order for email notification lists to alphabetical, ascending [`71cd579`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/71cd57927fd7670f9e6d99bc2c11c40b1fa6c802)
- Increasing generic client timeout to 20s to work around busy hosts [`812e844`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/812e8443bd83d31d6e363fd8d4a634f8bc2116fa)
- Fix for default sports naming pattern issue #269 [`bb3e609`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bb3e6095654c583166aa4755639485d21b90aacb)
- Fixing typo [`316500b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/316500b8e78b85fab133b217c9c5bedfed587430)
- We're moving! [`215942f`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/215942f445f7202aa3ec3387dbfae01f13c228ff)
- Code correction for scene conversion in Parsing cache [`a912140`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a912140ec582d9ea7484563b785fbe0df5c9e9f4)
- Fixes classification issues for determining if a show is air-by-date or sports or regular [`d14581b`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d14581b8ccd7d6ed38838b64655694d7f0c0e79c)
- More cache fixes [`cc02967`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cc0296783b264250974a2b8824da58d8858946a8)
- Fix for issue #182 [`51f691e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/51f691eeb221411ff6a847a256284148dc2bb92b)
- Fixed issue of unknown attribute keyword 'show' [`872056c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/872056cc5dbe6db2582e41f33dd4188202d5daf7)
- Fixes issue #161 [`a5836af`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/a5836afa4f225d87202260671c8e31b1eb7467d1)
- Fixed indent properly [`9fd3414`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9fd3414d3cadf4a60a565a2e8a6256e20262f6c6)
- Fixed indent [`c37e291`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c37e2911eab85248d580f45e525f615b5ba63764)
- Fix for sports naming issues [`ba660a1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/ba660a194206374ff5016e9fb7dff3fe2d24e204)
- Fix for strftime and thread locking issues [`826a9aa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/826a9aab6a942cf20b92a6d0a00e8ed18b9b5021)
- Fix for adding and importing shows [`94f688a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/94f688a1bc4ca530198907a957e9b0d4ee7a9eb7)
- Fix for backlog searches [`d8171ac`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d8171acc9718cf61b7d02aae4c72f203c3bd282e)
- HomePage sort by active show first. [`d1cf131`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/d1cf13174f381ad87e794f7bf433f9d6d3241687)
- Fix for ignore_words [`f10dd31`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f10dd3131fff3dc8dc123ba6f8e154c4bab1e607)
- Fix for Newznab providers [`26e259c`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/26e259c03606c6cc03ff06c15a8abd295a2ced00)
- fix indent [`5007b80`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5007b806a55a95162fc4cf1305dfd27bab856143)
- Misc code cleanup [`b3246b0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b3246b00496b0f8697ec41be3f95e32160b5db5e)
- forgot to remove print [`2af5b95`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/2af5b95a9d77db87eebbaf0c95c3bf67f3bb7352)
- Update scc.py [`5b713f0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5b713f0262644023ebbd335ea1172d9ffcd20a84)
- Fixed issue #37, ignore words [`4c84351`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/4c8435130680fd089b4bcb0bddc87946af1d5634)
- Fixed bug in cache controller [`c309e8a`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c309e8afc91426ec8c4150e78cfe40c73af821d0)
- Fixed IntegrityError caused by primary key not being unique [`97db8fd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/97db8fd408380721325a7cda8a428415546806be)
- Fix for issue #17 [`69691f9`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/69691f9d417f3cdf418dd9d1b0c9fd6062ba8c4f)
- Missed coverting scene_numbering table, fixed! [`999b1ba`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/999b1bafe000e52e098a598442275c5e0734c858)
- Previous fix to air dates did not take but this fix does correct the issue once causing malformed air dates or no air dates at all. [`f3c3327`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f3c33279b5162aa27bf18c3e084f57f282202398)
- Update show_name_helpers.py [`c0dedd0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c0dedd080f42b89505bf7dc42b512f2f925aecd9)
- Bugfix for XBMC 12+ metadata parser [`3bdebb4`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3bdebb4e6d7e61503cf825a833023184927a498a)
- Bugfix in the metadata code [`c9ddd63`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/c9ddd633eed8a16e52105a4639935bdf35b3134e)
- Made all init scripts executable [`1845bdd`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1845bdd5a9655e4bcce30eaf0f8c421907e95a7f)
- Remove building against python 2.5 as travis no longer supports it [`cebc0d2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cebc0d2d929fe8c2386a9f3f2c70496dfe230de8)
- Update comingEpisodes.tmpl to prevent a 'NotFound' error for cur_ep_enddate [`f3c1fa6`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/f3c1fa6b61102b041595023b6018d5336c11eb18)
- Fixed typo. [`b3bfe99`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b3bfe99faddc2ea0b9f2595901bcf9fec835bee0)
- Possible fix for failed to send torrent errors [`88d68cf`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/88d68cfe11e8f5ef80c87a8935121901d4460bc7)
- Removed unrequired version file. [`bfe0a00`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/bfe0a00cc7466559e547f0effeb7d91ab9500b97)
- Fix for missing indexerid number when performing naming pattern tests. [`267affa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/267affa5e99120df7ef39854201f80719003aacb)
- Fixed post-processing loop issue. [`5f0265e`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5f0265e769901f438b68ac4b18d2c9a320974dcb)
- Reverse proxy support fixed [`5124771`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/51247710bbdd647ab16aba00d4de050c6763b690)
- Fix for force update and autoreload [`9790b30`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9790b30b904d5fbccbcd0ef9be49ce9d7b3f65ad)
- Fixed anime button in settings [`500f387`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/500f387bad43090bbc9e2c9d3ab5393f2f7fb0dc)
- Reverted episode cache changes [`013f9a2`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/013f9a2134390abf75e5120bebdbf06ca1e4f993)
- Fix for startup issue due to dependant that was missing. [`1dc9138`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/1dc913824a0e91994cca88463cc6001914382276)
- Fixing UnboundLocalError when attempting to process nonexisting dir [`44d45ca`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/44d45ca760acf9305db15ad82e62f0d7823eaa53)
- Fix for issue #274, ebObj ref'd before assignment [`5ba99db`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/5ba99db64ef9f43c9f531560711931772196244b)
- Centering the header, by popular demand [`792e469`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/792e469e71027af41217764ad9cc9179c5c42725)
- Update network logos [`97226ae`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/97226ae6f3427c3bf25cc702ed54c645e083e20a)
- fix typo on network logo [`b8d7796`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/b8d7796318a89d3307e03b64264f54bf65f8906b)
- network logo's [`3c88cc1`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/3c88cc1cda9e4760992e6dc2089f2d8554bff07f)
- Renamed filename for wgn america network logo [`fc23454`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/fc23454a1e24df1c9005d519ca31a07da20d00ed)
- Updated network logo's to their current logo & made BBC logo's display nicer. [`cf1a3aa`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/cf1a3aa5d82544e39ea6021b322fa5b9072d3493)
- Fix, update and add some network specific logos as seen on the home page in "poster" view mode. [`e99d779`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/e99d779f7d9436758d4fa9f38bd0ccdb1a46f6e5)
- New logo design idea [`9bf38c0`](https://git.sickrage.ca/SiCKRAGE/sickrage/commit/9bf38c07aec2e9a00998192f7f420a33b1ee20a9)
================================================
FILE: COPYING.txt
================================================
GNU 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.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. 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
them 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 prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. 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.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey 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;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If 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 convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU 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 that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
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.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
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.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
The ultimate PVR application that downloads and manages your TV shows
Copyright (C) 2014 - echel0n
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
SiCKRAGE - Copyright (C) 2014 - echel0n
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
================================================
FILE: Dockerfile
================================================
FROM python:3.8-alpine3.12
MAINTAINER echel0n
ARG SOURCE_COMMIT
ENV SOURCE_COMMIT $SOURCE_COMMIT
ENV PYTHONIOENCODING="UTF-8"
ENV TZ 'Canada/Pacific'
COPY . /opt/sickrage/
RUN apk add --update --no-cache libffi-dev openssl-dev libxml2-dev libxslt-dev linux-headers build-base git tzdata unrar
RUN pip install -U pip setuptools
RUN pip install -r /opt/sickrage/requirements.txt
EXPOSE 8081
VOLUME /config /downloads /tv /anime
ENTRYPOINT ["python", "/opt/sickrage/SiCKRAGE.py"]
CMD ["--nolaunch", "--datadir=/config"]
================================================
FILE: MANIFEST.in
================================================
include README.txt
include COPYING.txt
include CHANGELOG.md
include requirements.txt
recursive-include sickrage *
global-exclude __pycache__
global-exclude *.py[cod]
================================================
FILE: README.txt
================================================
SiCKRAGE
=====
Automatic Video Library Manager for TV Shows.
It watches for new episodes of your favorite shows, and when they are posted it does its magic.
#### Features
- Kodi/XBMC library updates, poster/banner/fanart downloads, and NFO/TBN generation
- Configurable automatic episode renaming, sorting, and other processing
- Easily see what episodes you're missing, are airing soon, and more
- Automatic torrent/nzb searching, downloading, and processing at the qualities you want
- Largest list of supported torrent and nzb providers, both public and private
- Can notify Kodi, XBMC, Growl, Trakt, Twitter, and more when new episodes are available
- Searches TheTVDB.com and AniDB.net for shows, seasons, episodes, and metadata
- Episode status management allows for mass failing seasons/episodes to force retrying
- DVD Order numbering for returning the results in DVD order instead of Air-By-Date order
- Allows you to choose which series provider to have SiCKRAGE search its show info from when importing
- Automatic XEM Scene Numbering/Naming for seasons/episodes
- Available for any platform, uses a simple HTTP interface
- Specials and multi-episode torrent/nzb support
- Automatic subtitles matching and downloading
- Improved failed download handling
- DupeKey/DupeScore for NZBGet 12+
- Real SSL certificate validation
- Supports Anime shows
#### Installation
$ pip install sickrage
$ sickrage
#### Important
Before using this with your existing database (sickrage.db or sickbeard.db) please make a backup copy of it and delete
any other database files such as cache.db and failed.db if present.
We HIGHLY recommend starting out with no database files at all to make this a fresh start but the choice is at your own
risk.
================================================
FILE: SiCKRAGE.py
================================================
#!/usr/bin/env python3
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
from sickrage import main
if __name__ == '__main__':
main()
================================================
FILE: build_protos.bat
================================================
.\protoc.exe --proto_path=.\protos --python_out=.\sickrage\core\amqp\protos .\protos\*.proto
================================================
FILE: changelog-template.md
================================================
<% if(logo) { %><%= '\n\n' %><% } %># <%= title %>
<% if(intro) { %><%= '\n' %>_<%= intro %>_<%= '\n' %><% } %>
<% if(version) { %>##<% if(version.date){ %><%= version.date %><% } %><%= '\n' %><% } %>
<% _.forEach(sections, function(section){
if(section.commitsCount > 0) { %>
## <%= section.title %>
<% _.forEach(section.commits, function(commit){ %> - <%= printCommit(commit, true) %><% }) %>
<% _.forEach(section.components, function(component){ %> - **<%= component.name %>**
<% _.forEach(component.commits, function(commit){ %> - <%= printCommit(commit, true) %><% }) %>
<% }) %>
<% } %>
<% }) %>
================================================
FILE: checksum-generator.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import hashlib
import os
from pathlib import Path
main_dir = Path(__file__).parent
prog_dir = main_dir.joinpath('sickrage')
checksum_file = prog_dir.joinpath('checksums.md5')
def md5(filename):
blocksize = 8192
hasher = hashlib.md5()
with open(filename, 'rb') as afile:
buf = afile.read(blocksize)
while len(buf) > 0:
hasher.update(buf)
buf = afile.read(blocksize)
return hasher.hexdigest()
with open(checksum_file, "wb") as fp:
for root, dirs, files in os.walk(prog_dir):
for file in files:
full_filename = Path(str(root).replace(str(prog_dir), 'sickrage')).joinpath(file)
if full_filename != checksum_file:
fp.write('{} = {}\n'.format(full_filename, md5(full_filename)).encode())
print('Finished generating {}'.format(checksum_file))
================================================
FILE: checksum-validator.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import hashlib
from pathlib import Path
main_dir = Path(__file__).parent
prog_dir = main_dir.joinpath('sickrage')
checksum_file = prog_dir.joinpath('checksums.md5')
def md5(filename):
blocksize = 8192
hasher = hashlib.md5()
with open(filename, 'rb') as afile:
buf = afile.read(blocksize)
while len(buf) > 0:
hasher.update(buf)
buf = afile.read(blocksize)
return hasher.hexdigest()
with open(checksum_file, "rb") as fp:
failed = False
for line in fp.readlines():
file, checksum = line.decode().strip().split(' = ')
full_filename = main_dir.joinpath(file)
if full_filename != checksum_file:
if not full_filename.exists() or md5(full_filename) != checksum:
print('SiCKRAGE file {} checksum invalid'.format(full_filename))
failed = True
if not failed:
print('SiCKRAGE file checksums are all valid')
================================================
FILE: crowdin.yaml
================================================
project_identifier: sickragetv
api_key_env: CROWDIN_API_KEY
base_url: 'https://api.crowdin.com'
base_path: .
files:
- source: /sickrage/locale/messages.pot
translation: /sickrage/locale/%locale_with_underscore%/LC_MESSAGES/messages.po
================================================
FILE: docker-compose.yml
================================================
version: '2'
services:
sickrage:
container_name: sickrage
build: .
ports:
- 8081:8081
volumes:
- /path/to/sickrage/data:/root/.sickrage
- /path/to/downloads:/downloads
- /path/to/tv:/tv
- /path/to/anime:/anime
environment:
- TZ=Canada/Pacific
# - LANG=en_US.UTF-8
# - LANGUAGE=en_US:en
# - LC_ALL=en_US.UTF-8
================================================
FILE: manifests/deployment.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
name: __CI_COMMIT_REF_SLUG__
namespace: __KUBE_NAMESPACE__
labels:
app: __CI_COMMIT_REF_SLUG__
ref: __CI_ENVIRONMENT_SLUG__
spec:
replicas: 1
selector:
matchLabels:
app: __CI_COMMIT_REF_SLUG__
ref: __CI_ENVIRONMENT_SLUG__
template:
metadata:
labels:
app: __CI_COMMIT_REF_SLUG__
ref: __CI_ENVIRONMENT_SLUG__
spec:
containers:
- name: app
image: __CI_REGISTRY_IMAGE__:__VERSION__
imagePullPolicy: Always
env:
- name: TZ
value: "Canada/Pacific"
- name: WEB_ROOT
value: __CI_COMMIT_REF_SLUG__
ports:
- containerPort: 8081
imagePullSecrets:
- name: gitlab-registry
================================================
FILE: manifests/ingress.yaml
================================================
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: __CI_COMMIT_REF_SLUG__
namespace: __KUBE_NAMESPACE__
labels:
app: __CI_COMMIT_REF_SLUG__
ref: __CI_ENVIRONMENT_SLUG__
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- hosts:
- review.sickrage.ca
secretName: sickrage-ca-tls
rules:
- host: review.sickrage.ca
http:
paths:
- path: /__CI_COMMIT_REF_SLUG__
backend:
serviceName: __CI_COMMIT_REF_SLUG__
servicePort: 80
================================================
FILE: manifests/service.yaml
================================================
apiVersion: v1
kind: Service
metadata:
name: __CI_COMMIT_REF_SLUG__
namespace: __KUBE_NAMESPACE__
labels:
app: __CI_COMMIT_REF_SLUG__
ref: __CI_ENVIRONMENT_SLUG__
spec:
type: ClusterIP
ports:
- port: 80
protocol: TCP
targetPort: 8081
selector:
app: __CI_COMMIT_REF_SLUG__
================================================
FILE: package.json
================================================
{
"name": "sickrage",
"version": "10.0.71",
"private": true,
"repository": {
"type": "git",
"url": "git+https://git.sickrage.ca/SiCKRAGE/sickrage.git"
},
"bugs": {
"url": "https://forums.sickrage.ca"
},
"homepage": "https://www.sickrage.ca",
"scripts": {
"build": "webpack --config webpack.config.js"
},
"devDependencies": {
"@fortawesome/fontawesome-free": "~5.14.0",
"@sentry/browser": "~5.20.1",
"@sentry/integrations": "~5.20.1",
"@sentry/webpack-plugin": "~1.12.0",
"animate.css": "~3.7.2",
"autoprefixer": "~9.8.5",
"babel": "~6.23.0",
"babel-core": "~6.26.3",
"babel-eslint": "~8.2.5",
"babel-loader": "~7.1.5",
"babel-plugin-add-module-exports": "~0.2.1",
"babel-preset-env": "~1.7.0",
"bootstrap": "~4.4.1",
"bootstrap-formhelpers": "echel0n/BootstrapFormHelpers",
"clean-webpack-plugin": "~3.0.0",
"css-loader": "~3.6.0",
"eslint": "~6.8.0",
"eslint-loader": "~4.0.0",
"file-loader": "~6.0.0",
"gettext-parser": "~2.1.0",
"graceful-fs": "~4.2.4",
"imagesloaded": "~4.1.4",
"isotope-layout": "~3.0.6",
"jquery": "~3.5.1",
"jquery-backstretch": "~2.1.16",
"jquery-bridget": "~2.0.1",
"jquery-confirm": "~3.3.2",
"jquery-form": "~4.2.2",
"jquery-ui": "~1.12.1",
"jquery-validation": "~1.19.2",
"material-design-icons": "~3.0.1",
"mini-css-extract-plugin": "~0.4.1",
"node-sass": "~4.14.1",
"nonblockjs": "~1.0.8",
"optimize-css-assets-webpack-plugin": "~5.0.3",
"pnotify": "~4.0.0",
"popper.js": "~1.16.1",
"sass-loader": "~8.0.2",
"tablesorter": "~2.30.7",
"timeago": "~1.6.3",
"toggle-checkbox-radio": "~2.0.2",
"tokenfield": "~0.9.9",
"tooltipster": "~4.2.6",
"ttag": "~1.7.22",
"underscore": "~1.9.1",
"webpack": "^4.44.2",
"webpack-cli": "^4.8.0",
"webpack-spritesmith": "~1.1.0"
},
"dependencies": {
"auto-changelog": "~2.2.1",
"yarn": "^1.22.15"
}
}
================================================
FILE: protos/announcement_v1.proto
================================================
syntax = "proto3";
package app.protobufs.v1;
message CreatedAnnouncementResponse {
string ahash = 1;
string title = 2;
string description = 3;
string image = 4;
string date = 5;
}
message DeletedAnnouncementResponse {
string ahash = 1;
}
================================================
FILE: protos/network_timezone_v1.proto
================================================
syntax = "proto3";
package app.protobufs.v1;
message SavedNetworkTimezoneResponse {
string network = 1;
string timezone = 2;
}
message DeletedNetworkTimezoneResponse {
string network = 1;
}
================================================
FILE: protos/search_provider_url_v1.proto
================================================
syntax = "proto3";
package app.protobufs.v1;
message SavedSearchProviderUrlResponse {
string provider_id = 1;
string provider_url = 2;
}
================================================
FILE: protos/server_certificate_v1.proto
================================================
syntax = "proto3";
package app.protobufs.v1;
message SavedServerCertificateResponse {
string certificate = 1;
string private_key = 2;
}
================================================
FILE: protos/updates_v1.proto
================================================
syntax = "proto3";
package app.protobufs.v1;
message UpdatedAppResponse {
bool force = 1;
}
================================================
FILE: readme.md
================================================

Automatic Video Library Manager for TV Shows. It watches for new episodes of your favorite shows, and when they are posted it does its magic.
#### Dependencies
- To run SiCKRAGE from source you will need Python 3.5+
- To install requirements run 'pip install -r requirements.txt' from install folder
#### Features
- Kodi/XBMC library updates, poster/banner/fanart downloads, and NFO/TBN generation
- Configurable automatic episode renaming, sorting, and other processing
- Easily see what episodes you're missing, are airing soon, and more
- Automatic torrent/nzb searching, downloading, and processing at the qualities you want
- Largest list of supported torrent and nzb providers, both public and private
- Can notify Kodi, XBMC, Growl, Trakt, Twitter, and more when new episodes are available
- Searches TheTVDB.com and AniDB.net for shows, seasons, episodes, and metadata
- Episode status management allows for mass failing seasons/episodes to force retrying
- DVD Order numbering for returning the results in DVD order instead of Air-By-Date order
- Allows you to choose which series provider to have SiCKRAGE search its show info from when importing
- Automatic XEM Scene Numbering/Naming for seasons/episodes
- Available for any platform, uses a simple HTTP interface
- Specials and multi-episode torrent/nzb support
- Automatic subtitles matching and downloading
- Improved failed download handling
- DupeKey/DupeScore for NZBGet 12+
- Real SSL certificate validation
- Supports Anime shows
#### Screenshots
- [Desktop (Full-HD)](https://imgur.com/a/4fpBk)
- [Mobile](https://imgur.com/a/WPyG6)
#### Links
- [Support Forums](https://forums.sickrage.ca/)
- [FAQ](https://git.sickrage.ca/SiCKRAGE/sickrage/wikis/Frequently-Asked-Questions)
- [Wiki](https://git.sickrage.ca/SiCKRAGE/sickrage/wikis/home)
- [Supported providers](https://git.sickrage.ca/SiCKRAGE/sickrage/wikis/SickRage-Search-Providers)
- [Changes](https://git.sickrage.ca/SiCKRAGE/sickrage/raw/master/CHANGELOG.md)
#### Important
Before using this with your existing database sickrage.db please make a backup copy of it and delete any other database files such as cache.db and failed.db if present, We HIGHLY recommend starting out with no database files at all to make this a fresh start but the choice is at your own risk
================================================
FILE: renovate.json
================================================
{
"extends": [
"config:base",
":assignee(echel0n)"
],
"baseBranches": [
"develop"
],
"enabledManagers": [
"pip_requirements",
"poetry"
],
"python": {
"commitMessageAction": "Update Python",
"managerBranchPrefix": "py/",
"labels": [
"dependencies",
"python"
]
}
}
================================================
FILE: requirements-dev.txt
================================================
twine
crowdin-cli-py
babel
tox
mako
pytest
================================================
FILE: requirements.txt
================================================
aenum==2.2.4
alembic==1.4.2
apispec==4.0.0
apispec-webframeworks==0.5.2
appdirs==1.4.4
APScheduler==3.6.3
arrow==0.15.8
asn1crypto==1.4.0
attrs==19.3.0
babelfish==0.6.0
beautifulsoup4==4.10.0
bencode.py==4.0.0
bleach==3.3.0
CacheControl==0.12.6
certifi==2021.5.30
cffi==1.14.1
chardet==3.0.4
cleverdict==1.9.2
click==7.1.2
cloudscraper==1.2.46
configobj==5.0.6
cryptography==3.3.2
decorator==4.4.2
deluge-client==1.9.0
dirsync==2.2.5
dogpile.cache==1.0.2
ecdsa==0.14.1
enzyme==0.4.1
fake-useragent==0.1.11
feedparser==6.0.8
future==0.18.2
gntp==1.0.3
greenlet==1.1.2
guessit==3.1.1
hachoir==3.1.1
html5lib==1.1
httplib2==0.18.1
idna==2.10
importlib-metadata==4.11.3; python_version >= '3.7'
importlib-metadata==4.8.3; python_version == '3.6'
ipaddress==1.0.23
knowit==0.2.4
lockfile==0.12.2
lxml==4.8.0
Mako==1.1.3
markdown2==2.3.9
MarkupSafe==1.1.1
marshmallow==3.8.0
marshmallow-enum==1.5.1
marshmallow-sqlalchemy==0.23.1
msgpack==1.0.0
MultipartPostHandler==0.1.0
mutagen==1.45.1
oauth2==1.9.0.post1
oauthlib==3.1.0
packaging==20.4
pbr==5.4.5
pika==1.2.0
Pint==0.14
profilehooks==1.11.2
protobuf==3.19.4
pyasn1==0.4.8
pyasn1-modules==0.2.8
pycparser==2.20
PyJWT==1.7.1
pymediainfo==4.2.1
PyMySQL==0.10.0
pynzb==0.1.0
pyparsing==2.4.7
pysrt==1.1.2
python-dateutil==2.7.5
python-editor==1.0.4
python-jose==3.2.0
python-keycloak-client==0.2.3
python-twitter==3.5
pytz==2020.1
pyxdg==0.26
PyYAML==5.4.1
pywin32==304; sys_platform == 'win32'
rarfile==3.1
rebulk==2.0.1
requests==2.24.0
requests-oauthlib==1.3.0
requests-toolbelt==0.9.1
rsa==4.6
Send2Trash==1.5.0
sentry-sdk==0.19.5
service-identity==18.1.0
sgmllib3k==1.0.0
simplejson==3.17.2
six==1.15.0
soupsieve==2.0.1
SQLAlchemy==1.4.32
SQLAlchemy-Utils==0.38.2
stevedore==3.2.0
subliminal==2.1.0
telnetlib3==1.0.4
tornado==6.1
twilio==6.44.2
typing-extensions==4.1.1
tzlocal==2.1
Unidecode==1.1.1
urllib3==1.25.10
webencodings==0.5.1
xmltodict==0.12.0
zipp==3.1.0
================================================
FILE: runscripts/init.debian
================================================
#!/bin/sh
#
### BEGIN INIT INFO
# Provides: sickrage
# Required-Start: $local_fs $network $remote_fs
# Required-Stop: $local_fs $network $remote_fs
# Should-Start: $NetworkManager
# Should-Stop: $NetworkManager
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts instance of SickRage
# Description: starts instance of SickRage using start-stop-daemon
### END INIT INFO
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
# Source SickRage configuration
if [ -f /etc/default/sickrage ]; then
. /etc/default/sickrage
else
[ "${VERBOSE}" != no ] && echo "/etc/default/sickrage not found. Using default settings.";
fi
## Don't set -e
## Don't edit this file!
## Edit user configuation in /etc/default/sickrage to change
##
## SR_USER= #$RUN_AS, username to run sickrage under, the default is sickrage
## SR_GROUP= #$RUN_GROUP, group to run sickrage under, the default is sickrage
## SR_HOME= #$APP_PATH, the location of SiCKRAGE.py, the default is /opt/sickrage
## SR_DATA= #$DATA_DIR, the location of sickrage.db, cache, logs, the default is /opt/sickrage
## SR_PIDFILE= #$PID_FILE, the location of sickrage.pid, the default is /var/run/sickrage/sickrage.pid
## PYTHON_BIN= #$DAEMON, the location of the python binary, the default is /usr/bin/python3
## SR_OPTS= #$EXTRA_DAEMON_OPTS, extra cli option for sickrage, i.e. " --config=/home/sickrage/config.ini"
## SSD_OPTS= #$EXTRA_SSD_OPTS, extra start-stop-daemon option like " --group=users"
##
## EXAMPLE if want to run as different user
## add SR_USER=username to /etc/default/sickrage
## otherwise default sickrage is used
# Script name
NAME=$(basename "$0")
# App name
DESC=SickRage
## The defaults
# Run as username
RUN_AS=${SR_USER-sickrage}
# Run as group
RUN_GROUP=${SR_GROUP-sickrage}
# Path to app SR_HOME=path_to_app_SiCKRAGE.py
APP_PATH=${SR_HOME-/opt/sickrage}
# Data directory where sickrage.db, cache and logs are stored
DATA_DIR=${SR_DATA-/opt/sickrage}
# Path to store PID file
PID_FILE=${SR_PIDFILE-/var/run/sickrage/sickrage.pid}
# path to python bin
DAEMON=${PYTHON_BIN-/usr/bin/python3}
# Extra daemon option like: SR_OPTS=" --config=/home/sickrage/config.ini"
EXTRA_DAEMON_OPTS=${SR_OPTS-}
# Extra start-stop-daemon option like START_OPTS=" --group=users"
EXTRA_SSD_OPTS=${SSD_OPTS-}
##
PID_PATH=$(dirname $PID_FILE)
DAEMON_OPTS=" SiCKRAGE.py -q --daemon --nolaunch --pidfile=${PID_FILE} --datadir=${DATA_DIR} ${EXTRA_DAEMON_OPTS}"
##
test -x $DAEMON || exit 0
# Create PID directory if not exist and ensure the SickRage user can write to it
if [ ! -d $PID_PATH ]; then
mkdir -p $PID_PATH
chown $RUN_AS $PID_PATH
fi
if [ ! -d $DATA_DIR ]; then
mkdir -p $DATA_DIR
chown $RUN_AS $DATA_DIR
fi
if [ -e $PID_FILE ]; then
PID=`cat $PID_FILE`
if ! kill -0 $PID > /dev/null 2>&1; then
[ "$VERBOSE" != no ] && echo "Removing stale $PID_FILE"
rm -f $PID_FILE
fi
fi
start_sickrage() {
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
start-stop-daemon -d $APP_PATH -c $RUN_AS --group=${RUN_GROUP} $EXTRA_SSD_OPTS --start --quiet --pidfile $PID_FILE --exec $DAEMON -- $DAEMON_OPTS
RETVAL="$?"
case "${RETVAL}" in
# Service was started or was running already
0|1) [ "${VERBOSE}" != no ] && log_end_msg 0 ;;
# Service couldn't be started
2) [ "${VERBOSE}" != no ] && log_end_msg 1 ;;
esac
[ "${RETVAL}" = 2 ] && return 2
return 0
}
stop_sickrage() {
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
start-stop-daemon --stop --pidfile $PID_FILE --quiet --retry TERM/30/KILL/5
RETVAL="$?"
case "${RETVAL}" in
# Service was stopped or wasn't running
0|1) [ "${VERBOSE}" != no ] && log_end_msg 0 ;;
# Service couldn't be stopped
2) [ "${VERBOSE}" != no ] && log_end_msg 1 ;;
esac
[ "${RETVAL}" = 2 ] && return 2
[ -f "${PID_FILE}" ] && rm -f ${PID_FILE}
return 0
}
case "$1" in
start)
start_sickrage
exit $?
;;
stop)
stop_sickrage
exit $?
;;
restart|force-reload)
stop_sickrage
sleep 2
start_sickrage
exit $?
;;
status)
status_of_proc -p "$PID_FILE" "$DAEMON" "$DESC"
exit $?
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0
================================================
FILE: runscripts/init.fedora
================================================
#!/bin/sh
#
### BEGIN INIT INFO
# Provides: sickrage
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts SickRage
# Description: starts SickRage
### END INIT INFO
# Source function library.
. /etc/init.d/functions
# Source SickRage configuration
if [ -f /etc/sysconfig/sickrage ]; then
. /etc/sysconfig/sickrage
fi
prog=sickrage
lockfile=/var/lock/subsys/$prog
## Edit user configuation in /etc/sysconfig/sickrage to change
## the defaults
username=${SR_USER-sickrage}
homedir=${SR_HOME-/opt/sickrage}
datadir=${SR_DATA-/opt/sickrage}
pidfile=${SR_PIDFILE-/var/run/sickrage/sickrage.pid}
nice=${SR_NICE-}
python_bin=${PYTHON_BIN-/usr/bin/python3}
##
pidpath=`dirname ${pidfile}`
options=" --daemon --nolaunch --pidfile=${pidfile} --datadir=${datadir}"
# create PID directory if not exist and ensure the SickRage user can write to it
if [ ! -d $pidpath ]; then
mkdir -p $pidpath
chown $username $pidpath
fi
if [ ! -d $datadir ]; then
mkdir -p $datadir
chown $username $datadir
fi
start() {
# Start daemon.
echo -n $"Starting $prog: "
daemon --user=${username} --pidfile=${pidfile} ${nice} ${python_bin} ${homedir}/SiCKRAGE.py ${options}
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch $lockfile
return $RETVAL
}
stop() {
echo -n $"Shutting down $prog: "
killproc -p ${pidfile} ${python_bin}
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f $lockfile
return $RETVAL
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status $prog
;;
restart|force-reload)
stop
sleep 2
start
;;
try-restart|condrestart)
if status $prog > /dev/null; then
stop
start
fi
;;
reload)
exit 3
;;
*)
echo $"Usage: $0 {start|stop|status|restart|try-restart|force-reload}"
exit 2
esac
================================================
FILE: runscripts/init.freebsd
================================================
#!/bin/sh
#
# PROVIDE: sickrage
# REQUIRE: LOGIN
# KEYWORD: shutdown
#
# Add the following lines to /etc/rc.conf.local or /etc/rc.conf
# to enable this service:
#
# sickrage_enable (bool): Set to NO by default.
# Set it to YES to enable it.
# sickrage_user: The user account SickRage daemon runs as what
# you want it to be. It uses 'sickrage' user by
# default. Do not sets it as empty or it will run
# as root.
# sickrage_group: The group account SickRage daemon runs as what
# you want it to be. It uses 'sickrage' group by
# default. Do not sets it as empty or it will run
# as wheel.
# sickrage_dir: Directory where SickRage lives.
# Default: /usr/local/sickrage
# sickrage_datadir: Data directory for SickRage (DB, Logs, config)
# Default is same as sickrage_dir
. /etc/rc.subr
name="sickrage"
rcvar=${name}_enable
load_rc_config ${name}
: ${sickrage_enable:="NO"}
: ${sickrage_user:="sickrage"}
: ${sickrage_group:="sickrage"}
: ${sickrage_dir:="/usr/local/sickrage"}
: ${sickrage_datadir:="${sickrage_dir}"}
stop_cmd="sickrage_stop"
status_cmd="sickrage_status"
pidfile="/var/run/sickrage/sickrage.pid"
command="/usr/local/bin/python3 ${sickrage_dir}/SiCKRAGE.py -q --datadir ${sickrage_datadir} --nolaunch"
start_cmd="/usr/sbin/daemon -p ${pidfile} -u ${sickrage_user} -r -f $command"
start_precmd="sickrage_prestart"
sickrage_prestart() {
if [ -f ${pidfile} ]; then
rm -f ${pidfile}
echo "Removing stale pidfile."
elif [ ! -d ${pidfile%/*} ]; then
install -d -o ${sickrage_user} -g ${sickrage_group} ${pidfile%/*}
fi
if [ ! -d ${sickrage_datadir} ]; then
install -d -o ${sickrage_user} -g ${sickrage_group} ${sickrage_datadir}
fi
}
sickrage_stop() {
if [ -e "${pidfile}" ]; then
kill -s TERM `cat ${pidfile}`
else
echo "${name} is not running"
fi
}
sickrage_status() {
if [ -e "${pidfile}" ]; then
echo "${name} is running as pid `cat ${pidfile}`"
else
echo "${name} is not running"
fi
}
run_rc_command "$1"
================================================
FILE: runscripts/init.gentoo
================================================
#!/sbin/runscript
# Copyright 1999-2013 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# History
# -------
# 1/29 Created Richard Powell richard@powell.ws
# You will need to create a configuration file in order for this script
# to work properly. Please create /etc/conf.d/sickrage with the following:
#
# SICKRAGE_USER=
# SICKRAGE_GROUP=
# SICKRAGE_DIR=
# PATH_TO_PYTHON_3=/usr/bin/python3
# SICKRAGE_DATADIR=
# SICKRAGE_CONFDIR=
#
RUNDIR=/var/run/sickrage
depend() {
need net
}
get_pidfile() {
# Parse the config.ini file for the value of web_port in the General section
eval `sed -e 's/[[:space:]]*\=[[:space:]]*/=/g' \
-e 's/;.*$//' \
-e 's/[[:space:]]*$//' \
-e 's/^[[:space:]]*//' \
-e "s/^\(.*\)=\([^\"']*\)$/\1=\"\2\"/" \
< ${SICKRAGE_CONFDIR}/config.ini \
| sed -n -e "/^\[General\]/,/^\s*\[/{/^[^;].*\=.*/p;}"`
echo "${RUNDIR}/sickrage-${web_port}.pid"
}
start() {
ebegin "Starting Sickrage"
checkpath -q -d -o ${SICKRAGE_USER}:${SICKRAGE_GROUP} -m 0770 "${RUNDIR}"
start-stop-daemon \
--quiet \
--start \
--user ${SICKRAGE_USER} \
--group ${SICKRAGE_GROUP} \
--name sickrage \
--background \
--pidfile $(get_pidfile) \
--exec ${PATH_TO_PYTHON_3} \
-- \
${SICKRAGE_DIR}/SiCKRAGE.py \
-d \
--pidfile $(get_pidfile) \
--config ${SICKRAGE_CONFDIR}/config.ini \
--datadir ${SICKRAGE_DATADIR}
eend $?
}
start_pre() {
if [ "$RC_CMD" == "restart" ]; then
local pidfile=$(get_pidfile)
while [ -e ${pidfile} ]; do
sleep 1
done
fi
return 0
}
stop() {
local pidfile=$(get_pidfile)
local rc
ebegin "Stopping Sickrage"
}
================================================
FILE: runscripts/init.solaris11
================================================
Sickrage
================================================
FILE: runscripts/init.systemd
================================================
# Sickrage systemd service unit file
#
# Configuration Notes
#
# - Option names (e.g. ExecStart=, Type=) are case-sensitive)
#
# - Adjust User= and Group= to the user/group you want Sickrage to run as.
#
# - Optional adjust EnvironmentFile= path to configuration file
# Can ONLY be used for configuring extra options used in ExecStart.
# Putting a minus (-) in front of file means no error warning if the file doesn't exist
#
# - Adjust ExecStart= to point to your python and SickRage executables.
# The FIRST token of the command line must be an ABSOLUTE FILE NAME,
# then followed by arguments for the process.
# If no --datadir is given, data is stored in same dir as SiCKRAGE.py
# Arguments can also be set in EnvironmentFile (except python)
#
# - WantedBy= specifies which target (i.e. runlevel) to start Sickrage for.
# multi-user.target equates to runlevel 3 (multi-user text mode)
# graphical.target equates to runlevel 5 (multi-user X11 graphical mode)
#
### Example Using SickRage as daemon with pid file
# Type=forking
# PIDFile=/var/run/sickrage/sickrage.pid
# ExecStart=/usr/bin/python3 /opt/sickrage/SiCKRAGE.py -q --daemon --nolaunch --pidfile=/var/run/sickrage/sickrage.pid --datadir=/opt/sickrage
## Example Using SickRage as daemon without pid file
# Type=forking
# GuessMainPID=no
# ExecStart=/usr/bin/python3 /opt/sickrage/SiCKRAGE.py -q --daemon --nolaunch --datadir=/opt/sickrage
### Example Using simple
# Type=simple
# ExecStart=/usr/bin/python3 /opt/sickrage/SiCKRAGE.py -q --nolaunch
### Example Using simple with EnvironmentFile where SR_DATA=/home/sickrage/.sickrage in /etc/sickrage.conf
# Type=simple
# EnvironmentFile=/etc/sickrage.conf
# ExecStart=/usr/bin/python3 /opt/sickrage/SiCKRAGE.py -q --nolaunch --datadir=${SR_DATA}
### Configuration
[Unit]
Description=SickRage Daemon
After=network-online.target
[Service]
User=sickrage
Group=sickrage
Type=forking
GuessMainPID=no
ExecStart=/usr/bin/python3 /opt/sickrage/SiCKRAGE.py -q --daemon --nolaunch --datadir=/opt/sickrage
Restart=on-failure
TimeoutStopSec=300
[Install]
WantedBy=multi-user.target
================================================
FILE: runscripts/init.ubuntu
================================================
#!/bin/sh
#
### BEGIN INIT INFO
# Provides: sickrage
# Required-Start: $local_fs $network $remote_fs
# Required-Stop: $local_fs $network $remote_fs
# Should-Start: $NetworkManager
# Should-Stop: $NetworkManager
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts instance of SickRage
# Description: starts instance of SickRage using start-stop-daemon
### END INIT INFO
# Source SickRage configuration
if [ -f /etc/default/sickrage ]; then
. /etc/default/sickrage
else
echo "/etc/default/sickrage not found using default settings.";
fi
# Source init functions
. /lib/lsb/init-functions
# Script name
NAME=sickrage
# App name
DESC=SickRage
## Don't edit this file
## Edit user configuation in /etc/default/sickrage to change
##
## SR_USER= #$RUN_AS, username to run sickrage under, the default is sickrage
## SR_HOME= #$APP_PATH, the location of SiCKRAGE.py, the default is /opt/sickrage
## SR_DATA= #$DATA_DIR, the location of sickrage.db, cache, logs, the default is /opt/sickrage
## SR_PIDFILE= #$PID_FILE, the location of sickrage.pid, the default is /var/run/sickrage/sickrage.pid
## PYTHON_BIN= #$DAEMON, the location of the python binary, the default is /usr/bin/python3
## SR_OPTS= #$EXTRA_DAEMON_OPTS, extra cli option for sickrage, i.e. " --config=/home/sickrage/config.ini"
## SSD_OPTS= #$EXTRA_SSD_OPTS, extra start-stop-daemon option like " --group=users"
##
## EXAMPLE if want to run as different user
## add SR_USER=username to /etc/default/sickrage
## otherwise default sickrage is used
## The defaults
# Run as username
RUN_AS=${SR_USER-sickrage}
# Path to app SR_HOME=path_to_app_SiCKRAGE.py
APP_PATH=${SR_HOME-/opt/sickrage}
# Data directory where sickrage.db, cache and logs are stored
DATA_DIR=${SR_DATA-/opt/sickrage}
# Path to store PID file
PID_FILE=${SR_PIDFILE-/var/run/sickrage/sickrage.pid}
# path to python bin
DAEMON=${PYTHON_BIN-/usr/bin/python3}
# Extra daemon option like: SR_OPTS=" --config=/home/sickrage/config.ini"
EXTRA_DAEMON_OPTS=${SR_OPTS-}
# Extra start-stop-daemon option like START_OPTS=" --group=users"
EXTRA_SSD_OPTS=${SSD_OPTS-}
##
PID_PATH=`dirname $PID_FILE`
DAEMON_OPTS=" SiCKRAGE.py -q --daemon --nolaunch --pidfile=${PID_FILE} --datadir=${DATA_DIR} ${EXTRA_DAEMON_OPTS}"
##
test -x $DAEMON || exit 0
set -e
# Create PID directory if not exist and ensure the SickRage user can write to it
if [ ! -d $PID_PATH ]; then
mkdir -p $PID_PATH
chown $RUN_AS $PID_PATH
fi
if [ ! -d $DATA_DIR ]; then
mkdir -p $DATA_DIR
chown $RUN_AS $DATA_DIR
fi
if [ -e $PID_FILE ]; then
PID=`cat $PID_FILE`
if ! kill -0 $PID > /dev/null 2>&1; then
echo "Removing stale $PID_FILE"
rm $PID_FILE
fi
fi
start_sickrage() {
echo "Starting $DESC"
start-stop-daemon -d $APP_PATH -c $RUN_AS $EXTRA_SSD_OPTS --start --pidfile $PID_FILE --exec $DAEMON -- $DAEMON_OPTS
}
stop_sickrage() {
echo "Stopping $DESC"
start-stop-daemon --stop --pidfile $PID_FILE --retry 15
}
case "$1" in
start)
start_sickrage
;;
stop)
stop_sickrage
;;
restart|force-reload)
stop_sickrage
sleep 2
start_sickrage
;;
status)
status_of_proc -p "$PID_FILE" "$DAEMON" "$DESC"
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0
================================================
FILE: runscripts/init.upstart
================================================
# SickRage
#
# Configuration Notes
#
# - Adjust setuid and setgid to the user/group you want SickRage to run as.
# - For all other settings edit /etc/default/sickrage instead of this file.
#
# The following settings can be set in /etc/default/sickrage and are used to run SickRage.
# SR_HOME= #$APP_PATH, the location of SiCKRAGE.py, the default is /opt/sickrage
# SR_DATA= #$DATA_DIR, the location of sickrage.db, cache, logs, the default is /opt/sickrage
# SR_OPTS= #$EXTRA_DAEMON_OPTS, extra cli option for sickrage, i.e. " --config=/home/sickrage/config.ini"
description "SickRage Daemon"
start on runlevel [2345]
stop on runlevel [!2345]
kill timeout 30
setuid sickrage
setgid sickrage
respawn
respawn limit 10 5
script
if [ -f /etc/default/sickrage ]; then
. /etc/default/sickrage
else
echo "/etc/default/sickrage not found using default settings.";
fi
[ -z $SR_HOME ] && echo "I can't start SickRage if I don't know where it is"
if [ -n "$VIRTUALENV" ]; then
. "$VIRTUALENV/bin/activate"
fi
exec ${SR_HOME}/SiCKRAGE.py -q --nolaunch --datadir=${SR_DATA-SR_HOME} ${SR_OPTS-}
end script
================================================
FILE: setup.cfg
================================================
[bumpversion]
current_version = 10.0.71
commit = False
tag = False
parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\.(?P[a-z]+)(?P\d+))?
serialize =
{major}.{minor}.{patch}.{release}{dev}
{major}.{minor}.{patch}
[bumpversion:part:release]
optional_value = gamma
values =
dev
gamma
[metadata]
description-file = README.txt
[bdist_wheel]
universal = 1
[extract_messages]
width = 80
charset = utf-8
output_file = sickrage/locale/messages.pot
keywords = gt
copyright_holder = SiCKRAGE
msgid_bugs_address = support@sickrage.ca
add_comments = TRANSLATORS:
[compile_catalog]
directory = sickrage/locale
[init_catalog]
output_dir = sickrage/locale
input_file = sickrage/locale/messages.pot
[update_catalog]
output_dir = sickrage/locale
input_file = sickrage/locale/messages.pot
ignore_obsolete = true
previous = true
================================================
FILE: setup.py
================================================
import os
import shutil
import glob
from setuptools import setup, Command
from sickrage import __version__
def requirements():
with open(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'requirements.txt')) as f:
return f.read().splitlines(keepends=False)
class CleanCommand(Command):
"""Custom clean command to tidy up the project root."""
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
shutil.rmtree(os.path.abspath(os.path.join(os.path.dirname(__file__), 'build')), ignore_errors=True)
shutil.rmtree(os.path.abspath(os.path.join(os.path.dirname(__file__), '*.pyc')), ignore_errors=True)
shutil.rmtree(os.path.abspath(os.path.join(os.path.dirname(__file__), '*.tgz')), ignore_errors=True)
shutil.rmtree(os.path.abspath(os.path.join(os.path.dirname(__file__), 'sickrage.egg-info')), ignore_errors=True)
[os.remove(f) for f in glob.glob("dist/sickrage-*")]
cmd_class = {'clean': CleanCommand}
# Check for Babel availability
try:
from babel.messages.frontend import compile_catalog, extract_messages, init_catalog, update_catalog
cmd_class.update(dict(
compile_catalog=compile_catalog,
extract_messages=extract_messages,
init_catalog=init_catalog,
update_catalog=update_catalog
))
except ImportError:
pass
setup(
name='sickrage',
version=__version__,
description='Automatic Video Library Manager for TV Shows',
author='echel0n',
author_email='echel0n@sickrage.ca',
license='GPLv3',
url='https://git.sickrage.ca',
keywords=['sickrage', 'sickragetv', 'tv', 'torrent', 'nzb', 'video', 'echel0n'],
packages=['sickrage'],
install_requires=requirements(),
include_package_data=True,
python_requires='>=3',
platforms='any',
zip_safe=False,
test_suite='tests',
cmdclass=cmd_class,
entry_points={
"console_scripts": [
"sickrage=sickrage:main"
]
},
message_extractors={
'sickrage/core/webserver': [
('**/views/**.mako', 'mako', {'input_encoding': 'utf-8'})
],
'sickrage': [
('**.py', 'python', None)
],
'src': [
('**/js/*.min.js', 'ignore', None),
('**/js/*.js', 'javascript', {'input_encoding': 'utf-8'})
],
}
)
================================================
FILE: sickrage/__init__.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
__version__ = "10.0.71"
__install_type__ = ""
import sys
# sickrage requires python 3.6+
if sys.version_info < (3, 6, 0):
sys.exit("Sorry, SiCKRAGE requires Python 3.6+")
import argparse
import atexit
import gettext
import multiprocessing
import os
import pathlib
import re
import site
import subprocess
import threading
import time
import traceback
import pkg_resources
# pywin32 for windows service
try:
import win32api
import win32serviceutil
import win32evtlogutil
import win32event
import win32service
import win32ts
import servicemanager
from win32com.shell import shell, shellcon
except ImportError:
if __install_type__ == 'windows':
sys.exit("Sorry, SiCKRAGE requires Python module PyWin32.")
from signal import SIGTERM
app = None
MAIN_DIR = os.path.abspath(os.path.realpath(os.path.expanduser(os.path.dirname(os.path.dirname(__file__)))))
PROG_DIR = os.path.abspath(os.path.realpath(os.path.expanduser(os.path.dirname(__file__))))
LOCALE_DIR = os.path.join(PROG_DIR, 'locale')
CHANGELOG_FILE = os.path.join(MAIN_DIR, 'CHANGELOG.md')
REQS_FILE = os.path.join(MAIN_DIR, 'requirements.txt')
CHECKSUM_FILE = os.path.join(PROG_DIR, 'checksums.md5')
AUTO_PROCESS_TV_CFG_FILE = os.path.join(*[PROG_DIR, 'autoProcessTV', 'autoProcessTV.cfg'])
# add sickrage libs path to python system path
LIBS_DIR = os.path.join(PROG_DIR, 'libs')
if not (LIBS_DIR in sys.path) and not getattr(sys, 'frozen', False):
sys.path, remainder = sys.path[:1], sys.path[1:]
site.addsitedir(LIBS_DIR)
sys.path.extend(remainder)
# set system default language
gettext.install('messages', LOCALE_DIR, codeset='UTF-8', names=["ngettext"])
if __install_type__ == 'windows':
class SiCKRAGEService(win32serviceutil.ServiceFramework):
_svc_name_ = "SiCKRAGE"
_svc_display_name_ = "SiCKRAGE"
_svc_description_ = (
"Automated video library manager for TV shows. "
'Set to "automatic" to start the service at system startup. '
"You may need to login with a real user account when you need "
"access to network shares."
)
if hasattr(sys, "frozen"):
_exe_name_ = "SiCKRAGE.exe"
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
def SvcDoRun(self):
msg = "SiCKRAGE-service %s" % __version__
self.Logger(servicemanager.PYS_SERVICE_STARTED, msg + " has started")
start()
self.Logger(servicemanager.PYS_SERVICE_STOPPED, msg + " has stopped")
def SvcStop(self):
if app:
app.shutdown()
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def Logger(self, state, msg):
win32evtlogutil.ReportEvent(
self._svc_display_name_, state, 0, servicemanager.EVENTLOG_INFORMATION_TYPE, (self._svc_name_, msg)
)
class Daemon(object):
"""
Usage: subclass the Daemon class
"""
def __init__(self, pidfile, working_dir="/"):
self.stdin = getattr(os, 'devnull', '/dev/null')
self.stdout = getattr(os, 'devnull', '/dev/null')
self.stderr = getattr(os, 'devnull', '/dev/null')
self.pidfile = pidfile
self.working_dir = working_dir
self.pid = None
def daemonize(self):
"""
do the UNIX double-fork magic, see Stevens' "Advanced
Programming in the UNIX Environment" for details (ISBN 0201563177)
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
"""
try:
pid = os.fork()
if pid > 0:
# exit first parent
os._exit(0)
except OSError as e:
sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1)
os.setsid()
os.umask(0)
# do second fork
try:
pid = os.fork()
if pid > 0:
# exit from second parent
os._exit(0)
except OSError as e:
sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1)
# redirect standard file descriptors
sys.stdin = sys.__stdin__
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
sys.stdout.flush()
sys.stderr.flush()
si = open(self.stdin, 'r')
so = open(self.stdout, 'a+')
se = open(self.stderr, 'a+')
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
# write pidfile
atexit.register(self.delpid)
self.pid = os.getpid()
open(self.pidfile, 'w+').write("%s\n" % self.pid)
def delpid(self):
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
def start(self):
"""
Start the daemon
"""
# Check for a pidfile to see if the daemon already runs
try:
pf = open(self.pidfile, 'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None
if pid:
message = "pidfile %s already exist. Daemon already running?\n"
sys.stderr.write(message % self.pidfile)
sys.exit(1)
# Start the daemon
self.daemonize()
def stop(self):
"""
Stop the daemon
"""
# Get the pid from the pidfile
try:
pf = open(self.pidfile, 'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None
if not pid:
message = "pidfile %s does not exist. Daemon not running?\n"
sys.stderr.write(message % self.pidfile)
return # not an error in a restart
# Try killing the daemon process
try:
while 1:
os.kill(pid, SIGTERM)
time.sleep(0.1)
except OSError as err:
err = str(err)
if err.find("No such process") > 0:
self.delpid()
else:
sys.exit(1)
def version():
# Return the version number
return __version__
def install_type():
# Return the install type
if not __install_type__ and os.path.isdir(os.path.join(MAIN_DIR, '.git')):
return 'git'
else:
return __install_type__ or 'source'
def changelog():
# Return contents of CHANGELOG.md
with open(CHANGELOG_FILE) as f:
return f.read()
def check_requirements():
if os.path.exists(REQS_FILE):
with open(REQS_FILE) as f:
for line in f.readlines():
try:
req_name, req_version = line.strip().split('==', 1)
if 'python_version' in req_version:
m = re.search('(\d+.\d+.\d+).*(\d+.\d+)', req_version)
req_version = m.group(1)
python_version = m.group(2)
python_version_major = int(python_version.split('.')[0])
python_version_minor = int(python_version.split('.')[1])
if sys.version_info.major == python_version_major and sys.version_info.minor != python_version_minor:
continue
if not pkg_resources.get_distribution(req_name).version == req_version:
print('Updating requirement {} to {}'.format(req_name, req_version))
subprocess.check_call([sys.executable, "-m", "pip", "install", "--no-deps", "--no-cache-dir", line.strip()])
except pkg_resources.DistributionNotFound:
print('Installing requirement {}'.format(line.strip()))
subprocess.check_call([sys.executable, "-m", "pip", "install", "--no-deps", "--no-cache-dir", line.strip()])
except ValueError:
continue
def verify_checksums(remove_unverified=False):
valid_files = []
exempt_files = [pathlib.Path(__file__), pathlib.Path(CHECKSUM_FILE), pathlib.Path(AUTO_PROCESS_TV_CFG_FILE)]
if not os.path.exists(CHECKSUM_FILE):
return
with open(CHECKSUM_FILE, "rb") as fp:
for line in fp.readlines():
file, checksum = line.decode().strip().split(' = ')
full_filename = pathlib.Path(MAIN_DIR).joinpath(file)
valid_files.append(full_filename)
for root, dirs, files in os.walk(PROG_DIR):
for file in files:
full_filename = pathlib.Path(root).joinpath(file)
if full_filename in exempt_files or full_filename.suffix == '.pyc':
continue
if full_filename not in valid_files and PROG_DIR in str(full_filename):
try:
if remove_unverified:
print('Found unverified file {}, removed!'.format(full_filename))
full_filename.unlink()
else:
print('Found unverified file {}, you should delete this file manually!'.format(full_filename))
except OSError:
print('Unable to delete unverified filename {} during checksum verification, you should delete this file manually!'.format(full_filename))
def handle_windows_service():
if hasattr(sys, "frozen") and win32ts.ProcessIdToSessionId(win32api.GetCurrentProcessId()) == 0:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(SiCKRAGEService)
servicemanager.StartServiceCtrlDispatcher()
return True
if len(sys.argv) > 1 and sys.argv[1] in ("install", "update", "remove", "start", "stop", "restart", "debug"):
win32serviceutil.HandleCommandLine(SiCKRAGEService)
del sys.argv[1]
return True
def main():
multiprocessing.freeze_support()
# set thread name
threading.current_thread().name = 'MAIN'
# fix threading time bug
time.strptime("2012", "%Y")
if __install_type__ == 'windows':
if not handle_windows_service():
start()
else:
start()
def start():
global app
parser = argparse.ArgumentParser(
prog='sickrage',
description='Automated video library manager for TV shows'
)
parser.add_argument('-v', '--version',
action='version',
version=version())
parser.add_argument('-d', '--daemon',
action='store_true',
help='Run as a daemon (*NIX ONLY)')
parser.add_argument('-q', '--quiet',
action='store_true',
help='Disables logging to CONSOLE')
parser.add_argument('-p', '--port',
default=0,
type=int,
help='Override default/configured port to listen on')
parser.add_argument('-H', '--host',
default='',
help='Override default/configured host to listen on')
parser.add_argument('--dev',
action='store_true',
help='Enable developer mode')
parser.add_argument('--debug',
action='store_true',
help='Enable debugging')
parser.add_argument('--datadir',
default=os.path.abspath(os.path.join(os.path.expanduser("~"), '.sickrage')),
help='Overrides data folder for database, config, cache and logs (specify full path)')
parser.add_argument('--config',
default='config.ini',
help='Overrides config filename (specify full path and filename if outside datadir path)')
parser.add_argument('--pidfile',
default='sickrage.pid',
help='Creates a PID file (specify full path and filename if outside datadir path)')
parser.add_argument('--no_clean',
action='store_true',
help='Suppress cleanup of files not present in checksum.md5')
parser.add_argument('--nolaunch',
action='store_true',
help='Suppress launching web browser on startup')
parser.add_argument('--disable_updates',
action='store_true',
help='Disable application updates')
parser.add_argument('--web_root',
default='',
type=str,
help='Overrides URL web root')
parser.add_argument('--db_type',
default='sqlite',
help='Database type: sqlite or mysql')
parser.add_argument('--db_prefix',
default='sickrage',
help='Database prefix you want prepended to database table names')
parser.add_argument('--db_host',
default='localhost',
help='Database hostname (not used for sqlite)')
parser.add_argument('--db_port',
default='3306',
help='Database port number (not used for sqlite)')
parser.add_argument('--db_username',
default='sickrage',
help='Database username (not used for sqlite)')
parser.add_argument('--db_password',
default='sickrage',
help='Database password (not used for sqlite)')
# Parse startup args
args = parser.parse_args()
# check requirements
# if install_type() not in ['windows', 'synology', 'docker', 'qnap', 'readynas', 'pip']:
# check_requirements()
# verify file checksums, remove unverified files
# verify_checksums(remove_unverified=not args.no_clean)
try:
from sickrage.core import Core
app = Core()
except ImportError:
sys.exit("Sorry, SiCKRAGE requirements need to be installed.")
try:
app.quiet = args.quiet
app.web_host = args.host
app.web_port = int(args.port)
app.web_root = args.web_root.lstrip('/').rstrip('/')
app.no_launch = args.nolaunch
app.disable_updates = args.disable_updates
app.developer = args.dev
app.db_type = args.db_type
app.db_prefix = args.db_prefix
app.db_host = args.db_host
app.db_port = args.db_port
app.db_username = args.db_username
app.db_password = args.db_password
app.debug = args.debug
app.data_dir = os.path.abspath(os.path.realpath(os.path.expanduser(args.datadir)))
app.cache_dir = os.path.abspath(os.path.realpath(os.path.join(app.data_dir, 'cache')))
app.config_file = args.config
daemonize = (False, args.daemon)[not sys.platform == 'win32']
pid_file = args.pidfile
if not os.path.isabs(app.config_file):
app.config_file = os.path.join(app.data_dir, app.config_file)
if not os.path.isabs(pid_file):
pid_file = os.path.join(app.data_dir, pid_file)
# add sickrage module to python system path
if not (PROG_DIR in sys.path) and not getattr(sys, 'frozen', False):
sys.path, remainder = sys.path[:1], sys.path[1:]
site.addsitedir(PROG_DIR)
sys.path.extend(remainder)
# Make sure that we can create the data dir
if not os.access(app.data_dir, os.F_OK):
try:
os.makedirs(app.data_dir, 0o744)
except os.error:
sys.exit("Unable to create data directory '" + app.data_dir + "'")
# Make sure we can write to the data dir
if not os.access(app.data_dir, os.W_OK):
sys.exit("Data directory must be writeable '" + app.data_dir + "'")
# Make sure that we can create the cache dir
if not os.access(app.cache_dir, os.F_OK):
try:
os.makedirs(app.cache_dir, 0o744)
except os.error:
sys.exit("Unable to create cache directory '" + app.cache_dir + "'")
# Make sure we can write to the cache dir
if not os.access(app.cache_dir, os.W_OK):
sys.exit("Cache directory must be writeable '" + app.cache_dir + "'")
# daemonize if requested
if daemonize:
app.no_launch = True
app.quiet = True
app.daemon = Daemon(pid_file, app.data_dir)
app.daemon.daemonize()
app.pid = app.daemon.pid
app.start()
from tornado.ioloop import IOLoop
IOLoop.current().start()
except (SystemExit, KeyboardInterrupt):
if app:
app.shutdown()
except Exception as e:
try:
# attempt to send exception to sentry
import sentry_sdk
sentry_sdk.capture_exception(e)
except ImportError:
pass
traceback.print_exc()
if __name__ == '__main__':
main()
================================================
FILE: sickrage/autoProcessTV/__init__.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
================================================
FILE: sickrage/autoProcessTV/autoProcessTV.cfg.sample
================================================
[sickrage]
host=localhost
port=8081
api_key=
web_root=
ssl=0
================================================
FILE: sickrage/autoProcessTV/autoProcessTV.py
================================================
#!/usr/bin/env python3
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import os.path
import sys
from configparser import RawConfigParser, NoOptionError
import requests
def processEpisode(dir_to_process, org_nzb_name=None, status=None):
# Default values
host = "localhost"
port = "8081"
api_key = ""
ssl = 0
web_root = "/"
default_url = host + ":" + port + web_root
if ssl:
default_url = "https://" + default_url
else:
default_url = "http://" + default_url
# Get values from config_file
config = RawConfigParser()
config_filename = os.path.join(os.path.dirname(sys.argv[0]), "autoProcessTV.cfg")
if not os.path.isfile(config_filename):
print("ERROR: " + config_filename + " doesn\'t exist")
print("copy /rename " + config_filename + ".sample and edit\n")
print("Trying default url: " + default_url + "\n")
else:
try:
print("Loading config from " + config_filename + "\n")
with open(config_filename, "r") as fp:
config.readfp(fp)
# Replace default values with config_file values
host = config.get("sickrage", "host")
port = config.get("sickrage", "port")
api_key = config.get("sickrage", "api_key")
try:
ssl = int(config.get("sickrage", "ssl"))
except (NoOptionError, ValueError):
pass
try:
web_root = config.get("sickrage", "web_root")
if not web_root.startswith("/"):
web_root = "/" + web_root
if not web_root.endswith("/"):
web_root += "/"
except NoOptionError:
pass
except EnvironmentError as e:
print("Could not read configuration file: " + str(e))
sys.exit(1)
params = {
'cmd': 'postprocess',
'return_data': 0,
'path': dir_to_process
}
# if org_nzb_name is not None:
# params['nzbName'] = org_nzb_name
if status is not None:
params['failed'] = status
if ssl:
protocol = "https://"
else:
protocol = "http://"
url = "{}{}:{}{}api/{}/".format(protocol, host, port, web_root, api_key)
print("Opening URL: " + url)
try:
r = requests.get(url, params=params, verify=False, allow_redirects=False, stream=True)
for line in r.iter_lines():
if not line:
continue
print(line.strip())
except IOError as e:
print("Unable to open URL: " + str(e))
sys.exit(1)
if __name__ == "__main__":
print("This module is supposed to be used as import in other scripts and not run standalone.")
print("Use sabToSiCKRAGE instead.")
sys.exit(1)
================================================
FILE: sickrage/autoProcessTV/hellaToSiCKRAGE.py
================================================
#!/usr/bin/env python3
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import sys
from sickrage.autoProcessTV import autoProcessTV
if len(sys.argv) < 4:
print("No folder supplied - is this being called from HellaVCR?")
sys.exit()
else:
autoProcessTV.processEpisode(sys.argv[3], sys.argv[2])
================================================
FILE: sickrage/autoProcessTV/mediaToSiCKRAGE.py
================================================
#!/usr/bin/env python3
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import logging
import os
import sys
import time
from configparser import ConfigParser
import requests
sickragePath = os.path.split(os.path.split(sys.argv[0])[0])[0]
sys.path.append(sickragePath)
configFilename = os.path.join(sickragePath, "config.ini")
config = ConfigParser()
try:
with open(configFilename, "r") as fp:
config.readfp(fp)
except IOError as e:
print("Could not find/read SiCKRAGE config.ini: " + str(e))
print('Possibly wrong mediaToSiCKRAGE.py location. Ensure the file is in the autoProcessTV subdir of your '
'SiCKRAGE installation')
time.sleep(3)
sys.exit(1)
scriptlogger = logging.getLogger('mediaToSiCKRAGE')
formatter = logging.Formatter('%(asctime)s %(levelname)-8s MEDIATOSICKRAGE :: %(message)s', '%b-%d %H:%M:%S')
# Get the log dir setting from SB config
logdirsetting = config.get("General", "log_dir") if config.get("General", "log_dir") else 'logs'
# put the log dir inside the SiCKRAGE dir, unless an absolute path
logdir = os.path.normpath(os.path.join(sickragePath, logdirsetting))
logfile = os.path.join(logdir, 'sickrage.log')
try:
handler = logging.FileHandler(logfile)
except:
print('Unable to open/create the log file at ' + logfile)
time.sleep(3)
sys.exit()
handler.setFormatter(formatter)
scriptlogger.addHandler(handler)
scriptlogger.setLevel(logging.DEBUG)
def utorrent():
# print 'Calling utorrent'
if len(sys.argv) < 2:
scriptlogger.error('No folder supplied - is this being called from uTorrent?')
print("No folder supplied - is this being called from uTorrent?")
time.sleep(3)
sys.exit()
dirName = sys.argv[1]
nzbName = sys.argv[2]
return dirName, nzbName
def transmission():
dirName = os.getenv('TR_TORRENT_DIR')
nzbName = os.getenv('TR_TORRENT_NAME')
return dirName, nzbName
def deluge():
if len(sys.argv) < 4:
scriptlogger.error('No folder supplied - is this being called from Deluge?')
print("No folder supplied - is this being called from Deluge?")
time.sleep(3)
sys.exit()
dirName = sys.argv[3]
nzbName = sys.argv[2]
return dirName, nzbName
def blackhole():
if os.getenv('TR_TORRENT_DIR') is not None:
scriptlogger.debug('Processing script triggered by Transmission')
print("Processing script triggered by Transmission")
scriptlogger.debug('TR_TORRENT_DIR: ' + os.getenv('TR_TORRENT_DIR'))
scriptlogger.debug('TR_TORRENT_NAME: ' + os.getenv('TR_TORRENT_NAME'))
dirName = os.getenv('TR_TORRENT_DIR')
nzbName = os.getenv('TR_TORRENT_NAME')
else:
if len(sys.argv) < 2:
scriptlogger.error('No folder supplied - Your client should invoke the script with a Dir and a Relese Name')
print("No folder supplied - Your client should invoke the script with a Dir and a Relese Name")
time.sleep(3)
sys.exit()
dirName = sys.argv[1]
nzbName = sys.argv[2]
return dirName, nzbName
def main():
scriptlogger.info('Starting external PostProcess script ' + __file__)
host = config.get("General", "web_host")
port = config.get("General", "web_port")
api_key = config.get("General", "api_key")
try:
ssl = int(config.get("General", "enable_https"))
except (ConfigParser.NoOptionError, ValueError):
ssl = 0
try:
web_root = config.get("General", "web_root")
except ConfigParser.NoOptionError:
web_root = ""
tv_dir = config.get("General", "tv_download_dir")
use_torrents = int(config.get("General", "use_torrents"))
torrent_method = config.get("General", "torrent_method")
if not use_torrents:
scriptlogger.error('Enable Use Torrent on SiCKRAGE to use this Script. Aborting!')
print('Enable Use Torrent on SiCKRAGE to use this Script. Aborting!')
time.sleep(3)
sys.exit()
if not torrent_method in ['utorrent', 'transmission', 'deluge', 'blackhole']:
scriptlogger.error('Unknown Torrent Method. Aborting!')
print('Unknown Torrent Method. Aborting!')
time.sleep(3)
sys.exit()
dirName, nzbName = eval(locals()['torrent_method'])()
if dirName is None:
scriptlogger.error('MediaToSiCKRAGE script need a dir to be run. Aborting!')
print('MediaToSiCKRAGE script need a dir to be run. Aborting!')
time.sleep(3)
sys.exit()
if not os.path.isdir(dirName):
scriptlogger.error('Folder ' + dirName + ' does not exist. Aborting AutoPostProcess.')
print('Folder ' + dirName + ' does not exist. Aborting AutoPostProcess.')
time.sleep(3)
sys.exit()
if nzbName and os.path.isdir(os.path.join(dirName, nzbName)):
dirName = os.path.join(dirName, nzbName)
params = {
'cmd': 'postprocess',
'return_data': 0,
'path': dirName
}
# if nzbName is not None:
# params['nzbName'] = nzbName
if ssl:
protocol = "https://"
else:
protocol = "http://"
if host == '0.0.0.0':
host = 'localhost'
url = "{}{}:{}{}api/{}/".format(protocol, host, port, web_root, api_key)
scriptlogger.debug("Opening URL: " + url + ' with params=' + str(params))
print("Opening URL: " + url + ' with params=' + str(params))
try:
response = requests.get(url, params=params, verify=False, allow_redirects=False)
except Exception as err:
scriptlogger.error(': Unknown exception raised when opening url: ' + str(err))
time.sleep(3)
sys.exit('Unknown exception raised when opening url: ' + str(err))
if response.status_code == 401:
scriptlogger.error('Invalid SiCKRAGE API key, check your config')
time.sleep(3)
sys.exit('Invalid SiCKRAGE API key, check your config')
if response.ok:
scriptlogger.info('Script ' + __file__ + ' Succesfull')
print('Script ' + __file__ + ' Succesfull')
time.sleep(3)
sys.exit()
if __name__ == '__main__':
main()
================================================
FILE: sickrage/autoProcessTV/sabToSiCKRAGE.py
================================================
#!/usr/bin/env python3
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import sys
from sickrage.autoProcessTV import autoProcessTV
if len(sys.argv) < 2:
print("No folder supplied - is this being called from SABnzbd?")
sys.exit()
elif len(sys.argv) >= 8:
autoProcessTV.processEpisode(sys.argv[1], sys.argv[2], sys.argv[7])
elif len(sys.argv) >= 3:
autoProcessTV.processEpisode(sys.argv[1], sys.argv[2])
else:
autoProcessTV.processEpisode(sys.argv[1])
================================================
FILE: sickrage/checksums.md5
================================================
sickrage/version.txt = 80389d18c0540d2cec6ef65560121838
sickrage/checksums.md5 = d41d8cd98f00b204e9800998ecf8427e
sickrage/__init__.py = 1907c97a7ad1e7e783e442587c2ace55
sickrage/libs/__init__.py = d41d8cd98f00b204e9800998ecf8427e
sickrage/libs/upnpclient/const.py = 6239b8dea2367eda47279e4c5f0dfea4
sickrage/libs/upnpclient/errors.py = 5d93a721620f78934746366f8703df97
sickrage/libs/upnpclient/soap.py = b2fa5fe86bd8e6ae8697673b9b397c02
sickrage/libs/upnpclient/marshal.py = dffd6ce90b56272499164a94ba0c2184
sickrage/libs/upnpclient/upnp.py = 6fe2d7a0fe23f6010bf50db977b86a61
sickrage/libs/upnpclient/ssdp.py = d7e4399530dc38ee0f6fd16394cac694
sickrage/libs/upnpclient/__init__.py = 0bd05e7c1ce885552b2635e34014bdc0
sickrage/libs/upnpclient/util.py = f56420ccaf0b0c4993afc7d3ed7259ae
sickrage/libs/rtorrentlib/err.py = 854586c8a62a729ee5cb76160faf46b4
sickrage/libs/rtorrentlib/torrent.py = 5a8c95780e00400272387f381f2b6b88
sickrage/libs/rtorrentlib/peer.py = 82a7cc0719efe52bad4621e55bdae520
sickrage/libs/rtorrentlib/tracker.py = 10292802b5596befaee98ab9454441b8
sickrage/libs/rtorrentlib/__init__.py = 9b76081595c232aee31a509cb444fd12
sickrage/libs/rtorrentlib/common.py = 9c21c477185926b3179b63578089d790
sickrage/libs/rtorrentlib/group.py = b278d6fe78a66b38062094e1a6df26e7
sickrage/libs/rtorrentlib/file.py = 7c055f79ddecbe33545446ad38ba8fac
sickrage/libs/rtorrentlib/lib/bencode.py = 7064362de54d8fc451b964c1be3e87e8
sickrage/libs/rtorrentlib/lib/torrentparser.py = f0294a3a4e9cfcd4f5c9ee1cd983dd08
sickrage/libs/rtorrentlib/lib/__init__.py = d41d8cd98f00b204e9800998ecf8427e
sickrage/libs/rtorrentlib/lib/xmlrpc/http.py = 1588fdf863274afe3cc36170fb656322
sickrage/libs/rtorrentlib/lib/xmlrpc/basic_auth.py = dd81c7f652d9497c68c3311ebf235495
sickrage/libs/rtorrentlib/lib/xmlrpc/scgi.py = f04e76687cdfbfa948e808a6fee694e0
sickrage/libs/rtorrentlib/lib/xmlrpc/requests_transport.py = 93fb55b8ebd0a1f63e75835221c10b78
sickrage/libs/rtorrentlib/lib/xmlrpc/__init__.py = d41d8cd98f00b204e9800998ecf8427e
sickrage/libs/rtorrentlib/rpc/__init__.py = 1925ee27d140b1bd5c1dcb88dfbc5e83
sickrage/libs/trakt/helpers.py = 053c8ece2ee697012f03ce4144f5516d
sickrage/libs/trakt/version.py = df03931d819a5f93f962937177b68838
sickrage/libs/trakt/client.py = 90e73722d3bd9519dfde072c59ca8ab6
sickrage/libs/trakt/hooks.py = 34fb5915418039627b6d1aed34f0dc9e
sickrage/libs/trakt/__init__.py = 11a9bad64ffd444014205143bf1761d7
sickrage/libs/trakt/sphinxext.py = fda5ccce94aaa907e352d2c6cfec5905
sickrage/libs/trakt/objects/rating.py = 04c8a80eb301c747a92ff4a0164cb5cc
sickrage/libs/trakt/objects/video.py = 6389fb533efb6bba2d03e72d8b78aadf
sickrage/libs/trakt/objects/episode.py = 97b5f9aea24a5c8977f9ab430d328ecc
sickrage/libs/trakt/objects/comment.py = 1b4f03f887f6dfa0f744ed3fc402fc27
sickrage/libs/trakt/objects/media.py = d00bd4016769dea9cad5d806ac8a4f5a
sickrage/libs/trakt/objects/movie.py = cced4cfcae4b8d13bdbcc0d0050eee92
sickrage/libs/trakt/objects/person.py = 276eed56d9578158b5e72a44bfb365ba
sickrage/libs/trakt/objects/__init__.py = 80aa9a91c991c0415689e21a4da58086
sickrage/libs/trakt/objects/show.py = 53a57bf75c4fc163462ccebf1cd36500
sickrage/libs/trakt/objects/season.py = f8241d0bf4f35d39ed1d96875661898e
sickrage/libs/trakt/objects/list/custom.py = f76003a8f1c6feb9f5220a9c2d6cd56f
sickrage/libs/trakt/objects/list/base.py = fb2d334ef71c93ff69ce6086e67b70df
sickrage/libs/trakt/objects/list/__init__.py = 1f79707e598f3d32463dd76b603e0532
sickrage/libs/trakt/objects/core/helpers.py = 3f46eca852679cbc8bb5a56716c27b3f
sickrage/libs/trakt/objects/core/__init__.py = d41d8cd98f00b204e9800998ecf8427e
sickrage/libs/trakt/interfaces/auth.py = 8cd3e51be4424bbc37d03cd6d38964cd
sickrage/libs/trakt/interfaces/search.py = 141b513fafd808ee9923b0159e7286bb
sickrage/libs/trakt/interfaces/calendars.py = 95b8ee8d289ab898e53644caaece9c36
sickrage/libs/trakt/interfaces/recommendations.py = e447fd7e1a031f16b63e2f9913e2d034
sickrage/libs/trakt/interfaces/__init__.py = 66e3511c03322045eb9ad3aa6003b10a
sickrage/libs/trakt/interfaces/scrobble.py = 818893221e1757530b72ede86df5b828
sickrage/libs/trakt/interfaces/sync/ratings.py = b0b3ef0efff73556f31c60866ccf64fa
sickrage/libs/trakt/interfaces/sync/watchlist.py = 94c5fdbdfa8628b8558e560523119a6a
sickrage/libs/trakt/interfaces/sync/playback.py = b437bfe7e4575a28d0f7e0884db0ea01
sickrage/libs/trakt/interfaces/sync/collection.py = cbd37c3781b948d83e2f63ff44656951
sickrage/libs/trakt/interfaces/sync/history.py = 13e1321a95b2e23420790d36420c72ec
sickrage/libs/trakt/interfaces/sync/watched.py = 24f24df6fa350c5fe246ef4c41b9d36d
sickrage/libs/trakt/interfaces/sync/__init__.py = acd2a1c81dccfcb4d5a2bb3af793a2ee
sickrage/libs/trakt/interfaces/sync/core/mixins.py = 217d9ca452d4eac30c956f568cc8147b
sickrage/libs/trakt/interfaces/sync/core/__init__.py = d41d8cd98f00b204e9800998ecf8427e
sickrage/libs/trakt/interfaces/base/__init__.py = c572fb03b23adabb95a5c5aaf77eb3f6
sickrage/libs/trakt/interfaces/oauth/device.py = 099fd9817324b0debe7ae15ffaef0619
sickrage/libs/trakt/interfaces/oauth/__init__.py = 5c876e3629b279acce12dcc7ba970be7
sickrage/libs/trakt/interfaces/oauth/pin.py = 0f577e8da86d72ca446482f85cf7ae8f
sickrage/libs/trakt/interfaces/movies/__init__.py = 51ae326e3b233bbeabaf30343b4ce8cc
sickrage/libs/trakt/interfaces/users/__init__.py = 1fe67497db3dc0d38941aa603408098f
sickrage/libs/trakt/interfaces/users/settings.py = a15c718341782c029f0dce50e8c9293a
sickrage/libs/trakt/interfaces/users/lists/list_.py = e56511c6b161bca6932176d8cbe3208d
sickrage/libs/trakt/interfaces/users/lists/__init__.py = 27bf6e910df32ec087f15831bfe60217
sickrage/libs/trakt/interfaces/shows/__init__.py = a6a0b3213e8ae531d817b7edd651dd2e
sickrage/libs/trakt/mapper/list_item.py = a419f792acaf3769a6a44159d27e96f9
sickrage/libs/trakt/mapper/search.py = 3355dd16ca07ff4aad2b9cd5e26d6879
sickrage/libs/trakt/mapper/comment.py = a0e172a8025e054e4e28c89ab83722b2
sickrage/libs/trakt/mapper/list.py = 3c24d9cf4884009e064410702bf411eb
sickrage/libs/trakt/mapper/sync.py = 3e341bb2bcb0d51a03e1d413b527271a
sickrage/libs/trakt/mapper/__init__.py = 9eec6156e9f43fce54b2443f51ca91d6
sickrage/libs/trakt/mapper/summary.py = 690c4a0416b27fe55cd67e584514e16b
sickrage/libs/trakt/mapper/core/base.py = 03eef199c624ab9a167067704593dead
sickrage/libs/trakt/mapper/core/__init__.py = d41d8cd98f00b204e9800998ecf8427e
sickrage/libs/trakt/core/helpers.py = 8cfab4ef03246b428ffdb49818f56670
sickrage/libs/trakt/core/http.py = 1745ee04342542ee8918664f764f0398
sickrage/libs/trakt/core/configuration.py = ef0a912fb6eed7c8bc4ec59fafd5c3c7
sickrage/libs/trakt/core/errors.py = da82abc917f11a40679212fd0f3a63fb
sickrage/libs/trakt/core/keylock.py = 13522249491d85e8c20cac1b4dce2ce0
sickrage/libs/trakt/core/pagination.py = 608ce69d264fe9df5bb5e0f467ccc64b
sickrage/libs/trakt/core/emitter.py = fce2647bb2d4c0d96d6721c38b0a074b
sickrage/libs/trakt/core/exceptions.py = ed407cdff70d291968d721b96152c705
sickrage/libs/trakt/core/context_collection.py = ec968901fae47aed4de56cf5f11d0796
sickrage/libs/trakt/core/__init__.py = d41d8cd98f00b204e9800998ecf8427e
sickrage/libs/trakt/core/request.py = 2a59bdb3bd14db424cdf92c11f68d601
sickrage/libs/trakt/core/context_stack.py = a9dfcdfd57731155768cbf997a0ae03b
sickrage/libs/fanart/errors.py = b4c88e71ca6b7fd1d408abf1c26d4c99
sickrage/libs/fanart/music.py = 5ec97fffa71740c46eb38872a9b26d84
sickrage/libs/fanart/tv.py = b7c3b4b97f943f5a2068169bd7b4c2f2
sickrage/libs/fanart/movie.py = 3908e99747a1dbed8457f1607d9797de
sickrage/libs/fanart/items.py = e51807329cfc25e9a738061509d63c88
sickrage/libs/fanart/immutable.py = 8dc58eb7a4625d1291c8226a9c9ac00a
sickrage/libs/fanart/__init__.py = a391ef168b87d4e21d483a499d871b79
sickrage/libs/adba/aniDBresponses.py = 97f8444354257d02f322669a139d3ba9
sickrage/libs/adba/aniDBcommands.py = b7e461bb7a24909e9bfdc010a584eabb
sickrage/libs/adba/aniDBfileInfo.py = 7df819d8881262eb4070be38d246bf94
sickrage/libs/adba/aniDBtvDBmaper.py = fd66ab7037e60853fb304112bc9edf3e
sickrage/libs/adba/aniDBAbstracter.py = 4dbaa4578b96d1e233b0e6d2696b68b9
sickrage/libs/adba/aniDBerrors.py = 0f0fb8904f48c5ec613e71c3a79599c8
sickrage/libs/adba/aniDBmaper.py = f7fd18dceae16e29fce39ab8f2c9142f
sickrage/libs/adba/aniDBlink.py = b261bb800495d34d5a64b5568d0238b2
sickrage/libs/adba/__init__.py = 5b00506b23b1a2bc72f1298886ab6a09
sickrage/series_providers/thetvdb.py = 529b60fcd23e61681f4b6c828d2337ac
sickrage/series_providers/helpers.py = 20f4de562e6bdbab2e6baa6d54cadd6a
sickrage/series_providers/cache.py = 633c4957cd49472265794310c6f31ad1
sickrage/series_providers/exceptions.py = 6b85b3a3a22ec33db1aff5b4244ae78c
sickrage/series_providers/__init__.py = 1ce8ff5179635877f3e42fe4f0bd3d71
sickrage/autoProcessTV/mediaToSiCKRAGE.py = f88a6679a211b1f97126c116e2c33b9c
sickrage/autoProcessTV/autoProcessTV.py = 6bdc9dedf433e140c523d04afa1c50ec
sickrage/autoProcessTV/hellaToSiCKRAGE.py = 9bc477abfd456aaba8d6bf46f2c59b1f
sickrage/autoProcessTV/sabToSiCKRAGE.py = e101d5495615b9b698b5034f3db05b80
sickrage/autoProcessTV/__init__.py = bfa892dee586740a3a618d3c1955156c
sickrage/autoProcessTV/autoProcessTV.cfg.sample = 1898594be662b83c22dde39414ddc4e9
sickrage/subtitles/__init__.py = 1c1eeb0beed3c6198ffe68ce0ed7f72d
sickrage/subtitles/providers/subscene.py = 32f7c970672aa416944fffaccc3c2349
sickrage/subtitles/providers/utils.py = 943371392d3e0a58432ee5928c865a48
sickrage/subtitles/providers/itasa.py = 02500026d8dbe2dfdb719d6b16c4de89
sickrage/subtitles/providers/wizdom.py = 490dfcceb11b368a0ecd8ce253e9775b
sickrage/subtitles/providers/__init__.py = d41d8cd98f00b204e9800998ecf8427e
sickrage/subtitles/converters/subscene.py = 8e79b99f48edee6430a7a7d3c659d856
sickrage/subtitles/converters/__init__.py = d41d8cd98f00b204e9800998ecf8427e
sickrage/subtitles/refiners/tv_episode.py = e53792a1cfc400aeac48919602b404da
sickrage/subtitles/refiners/release.py = 2f47898120c18d4f22fde2aa3fd6cfbd
sickrage/subtitles/refiners/__init__.py = 4e94a1192bc45368b8cc3cd5f6d1debc
sickrage/locale/messages.pot = 1612a208279cfc539c67472192365888
sickrage/locale/tr_TR/LC_MESSAGES/messages.po = 529040aafd4e574c726fbe9889137bc3
sickrage/locale/tr_TR/LC_MESSAGES/messages.mo = cea9f6fb0eb38677288ef0f04a8f8e12
sickrage/locale/pl_PL/LC_MESSAGES/messages.po = ea70b0256918b8ff22253b87f6ad27fa
sickrage/locale/pl_PL/LC_MESSAGES/messages.mo = 4dd3099555a212787482116de8d97425
sickrage/locale/pt_BR/LC_MESSAGES/messages.po = ae577b5f67188509fbc9eb17db58bffc
sickrage/locale/pt_BR/LC_MESSAGES/messages.mo = 2c21edf8079b70874d47000e96795bbb
sickrage/locale/pt_PT/LC_MESSAGES/messages.po = 66f8ec9ca2e1cae4e94780affb19913f
sickrage/locale/pt_PT/LC_MESSAGES/messages.mo = 2a32220584fd5c275edcda740487e013
sickrage/locale/fi_FI/LC_MESSAGES/messages.po = a48a75afd08b971f33d43e3a41f8fee4
sickrage/locale/fi_FI/LC_MESSAGES/messages.mo = 088f03c99626b3f9c0b1049b999e7aa3
sickrage/locale/cs_CZ/LC_MESSAGES/messages.po = 23dc292ec5dc186b329dc96332fe56e7
sickrage/locale/cs_CZ/LC_MESSAGES/messages.mo = 361c5b5f95e3257f62207151ae7f8d54
sickrage/locale/ro_RO/LC_MESSAGES/messages.po = 7d5cf9b918b9cdd0b1c54973474a58b3
sickrage/locale/ro_RO/LC_MESSAGES/messages.mo = a516f4b77d45a72ec8c08f57c4285ff4
sickrage/locale/af_ZA/LC_MESSAGES/messages.po = bd384bf1efcb443fff36388c6a244395
sickrage/locale/af_ZA/LC_MESSAGES/messages.mo = e286f1c3ea0e39cf26ec83965fc7a8a3
sickrage/locale/zh_CN/LC_MESSAGES/messages.po = 29ec12f1cf35ce0cce46deb829e7cd39
sickrage/locale/zh_CN/LC_MESSAGES/messages.mo = 5759de08185dc5e19f2fd168ef7723ae
sickrage/locale/he_IL/LC_MESSAGES/messages.po = f77a392290a5329400bd1c5cde20991e
sickrage/locale/he_IL/LC_MESSAGES/messages.mo = e6b02761e7eac491a91474657d0bcd09
sickrage/locale/fr_FR/LC_MESSAGES/messages.po = 49425e920f8f758e850a997823029049
sickrage/locale/fr_FR/LC_MESSAGES/messages.mo = a6164ddf31e639da13125e76a18c5717
sickrage/locale/no_NO/LC_MESSAGES/messages.po = 20c024a9f27a8ceb4d69e56cdec74104
sickrage/locale/no_NO/LC_MESSAGES/messages.mo = f6f6e9e09a3bc0a996a4ed19c67d8b06
sickrage/locale/en_US/LC_MESSAGES/messages.po = e715e42ec14f638a3249b4ed4cd45eaa
sickrage/locale/en_US/LC_MESSAGES/messages.mo = 8d08e2dd11b766a3ed5277272cd38463
sickrage/locale/ar_SA/LC_MESSAGES/messages.po = 2638d3da69ab41e3c36982ee9917a6df
sickrage/locale/ar_SA/LC_MESSAGES/messages.mo = a4965d9e9440ad1d99674e4f7b6bd82a
sickrage/locale/ca_ES/LC_MESSAGES/messages.po = 482932508adc851165b1a1be768fe3e2
sickrage/locale/ca_ES/LC_MESSAGES/messages.mo = 80f192584d2342b13b2aaedeab548cf0
sickrage/locale/ru_RU/LC_MESSAGES/messages.po = 34842a1e2c2b6e01285dd66597eccda3
sickrage/locale/ru_RU/LC_MESSAGES/messages.mo = f1b7dc915b911782697ce774c241e871
sickrage/locale/nl_NL/LC_MESSAGES/messages.po = f5448557eb95d88f1c4c13bbf944fb97
sickrage/locale/nl_NL/LC_MESSAGES/messages.mo = 8c6251894dfa2585e887484c880913fd
sickrage/locale/ja_JP/LC_MESSAGES/messages.po = 0869628f0fdbb736627470e6be09aa38
sickrage/locale/ja_JP/LC_MESSAGES/messages.mo = 27877952a91db73718f327437e2649ae
sickrage/locale/de_DE/LC_MESSAGES/messages.po = e42e2023ea1137fd72d0ade08d9ce7b0
sickrage/locale/de_DE/LC_MESSAGES/messages.mo = 0ca56f3c27a81f1f99f4fb0e48f1dbc1
sickrage/locale/sr_SP/LC_MESSAGES/messages.po = 896a1d5b632a3dc0ea64195c7adfbdd5
sickrage/locale/sr_SP/LC_MESSAGES/messages.mo = 5e8b16f088dc5804327e0a141f50c53a
sickrage/locale/it_IT/LC_MESSAGES/messages.po = 80f922eb64c893b082012a4636174dd1
sickrage/locale/it_IT/LC_MESSAGES/messages.mo = b8c3a2e12d9e925b1f8a7f93f92617d5
sickrage/locale/da_DK/LC_MESSAGES/messages.po = ec0c24ba4f60ac4db83a534d05f67376
sickrage/locale/da_DK/LC_MESSAGES/messages.mo = 533de195bc02c819f56b577517efe366
sickrage/locale/sv_SE/LC_MESSAGES/messages.po = b614bdf5e138b9b5ea816bf3982e7c27
sickrage/locale/sv_SE/LC_MESSAGES/messages.mo = c9c7171447f426c92e874267545f11a1
sickrage/locale/es_ES/LC_MESSAGES/messages.po = 0371c2a33be01f8f18a6912c4299fcbb
sickrage/locale/es_ES/LC_MESSAGES/messages.mo = 557814738307b8deaabe6e9848c0bed8
sickrage/locale/hu_HU/LC_MESSAGES/messages.po = fe7aa25cb40d0652d48d60f67b16e813
sickrage/locale/hu_HU/LC_MESSAGES/messages.mo = 711ad8556527ddb836b1962cb6872b00
sickrage/locale/el_GR/LC_MESSAGES/messages.po = c52de41433aa7d26d74d265f906775a0
sickrage/locale/el_GR/LC_MESSAGES/messages.mo = a694d4171277d2f88b4d588dfcfcb065
sickrage/locale/uk_UA/LC_MESSAGES/messages.po = fd0de6780a31381e546294904a5c4f96
sickrage/locale/uk_UA/LC_MESSAGES/messages.mo = 2fe577ad2cae75ad956b544f4c831fae
sickrage/locale/zh_TW/LC_MESSAGES/messages.po = 0ccf0dc6e1c53995baea7270f69a0f38
sickrage/locale/zh_TW/LC_MESSAGES/messages.mo = a8ba19fb61c98fa3e31d8e973b2c7af4
sickrage/locale/vi_VN/LC_MESSAGES/messages.po = efd0a97563c07d3c19752a6665eaf24b
sickrage/locale/vi_VN/LC_MESSAGES/messages.mo = 5592d96801cf86becbb7e5b14a0c23ac
sickrage/locale/ko_KR/LC_MESSAGES/messages.po = 9dd2db0adb5b5b99597400654be7044c
sickrage/locale/ko_KR/LC_MESSAGES/messages.mo = d03e00a6f37dbfba899267c4746c512e
sickrage/search_providers/__init__.py = 9b1bbd1b5aee0a2c1a7b1b30894ee31e
sickrage/search_providers/torrent/tokyotoshokan.py = 6565d0557d9bff21ef2ae341ab2e0703
sickrage/search_providers/torrent/limetorrents.py = b7823968977181204f4e469fb14c0270
sickrage/search_providers/torrent/magnetdl.py = 6e141ac610e2e66f2cda5abf60624ae3
sickrage/search_providers/torrent/kat.py = 53df712d62a519e68f3508c285da0d50
sickrage/search_providers/torrent/ncore.py = 1f8bcedb77c3681f3e2e8a08fed56f43
sickrage/search_providers/torrent/torrentday.py = 8828a03b3caf9b2a8aa3ac1952b9213f
sickrage/search_providers/torrent/torrentz.py = 2d9f4b4c6f56e51bc399cf74ff26b5fd
sickrage/search_providers/torrent/hdspace.py = d1ea7a3cf713e17a82d6798b36c5bdc5
sickrage/search_providers/torrent/filelist.py = 1579e2641a44e677743756f41812c523
sickrage/search_providers/torrent/speedcd.py = 4bf57fe1069b04058a306229b15da14c
sickrage/search_providers/torrent/btn.py = dfad684d5930b06da266d64ffc88d328
sickrage/search_providers/torrent/xthor.py = 269a26ca8541a7d7b8283f95348b96a6
sickrage/search_providers/torrent/tvchaosuk.py = 8c0e73f03e33cb2fe1df37ef3032dcf3
sickrage/search_providers/torrent/torrentproject.py = 2cc5c3c3136139fdaf4b6c9ac7bad641
sickrage/search_providers/torrent/scenetime.py = 22103020dbfbc8ee29ef19302d179739
sickrage/search_providers/torrent/norbits.py = 515632c8f53148f41f2f9f67425adbc5
sickrage/search_providers/torrent/torrentbytes.py = cf5f202812696889fb8a704a9852dd46
sickrage/search_providers/torrent/morethantv.py = 8fd0213a69de32857391a357bdf325d1
sickrage/search_providers/torrent/shazbat.py = f030a0047a5941306d6ed17714bc008e
sickrage/search_providers/torrent/bitcannon.py = 88fb396949c6115ca117d5d8fc08f6fe
sickrage/search_providers/torrent/gktorrent.py = b1058b6856cf70a9530907e17d8e36ce
sickrage/search_providers/torrent/hdtorrents.py = d2f594a461dd74a813d0e8b36887aa4f
sickrage/search_providers/torrent/nyaatorrents.py = 762a1001da55d344ee17335e7824372a
sickrage/search_providers/torrent/immortalseed.py = c1d475bee6a8ab2b34223325dfa0b39f
sickrage/search_providers/torrent/danishbits.py = 9f1e93960b682c2622ad34d2acbd4c52
sickrage/search_providers/torrent/hdbits.py = 21c72469a3182357a6ef53781cb111af
sickrage/search_providers/torrent/hounddawgs.py = 32611bae64787a83b9e4ea26675afc46
sickrage/search_providers/torrent/alpharatio.py = 6fbcc2a4ec3382980fe3002c06eba837
sickrage/search_providers/torrent/1337x.py = 5b88a3d4836c8afca7a098fad78f4a72
sickrage/search_providers/torrent/iptorrents.py = cde34f6a515d77ceeeb8b76508df6e75
sickrage/search_providers/torrent/torrentleech.py = a49fea7c6bf9f75b3db980a6390ee654
sickrage/search_providers/torrent/hd4free.py = 0461a46696ba071e93db0ac4950985b9
sickrage/search_providers/torrent/nebulance.py = c8cd09d625753bf252c9ddf759e1bd26
sickrage/search_providers/torrent/__init__.py = 2228e977ebea8966e27929f43e39cb67
sickrage/search_providers/torrent/newpct.py = 2e9d96949f04e844a53a0c0417ae9c9c
sickrage/search_providers/torrent/yggtorrent.py = 376f76eea00b2fe61ab0850958517da4
sickrage/search_providers/torrent/abnormal.py = fa083f028e682e45075e8497ce05d726
sickrage/search_providers/torrent/pretome.py = a7b1a9511059eb625baf425f0fe85c42
sickrage/search_providers/torrent/thepiratebay.py = f29c407289e7389437548875583348cc
sickrage/search_providers/nzb/anizb.py = e6a455928ecca9ebe938f9a984848bff
sickrage/search_providers/nzb/binsearch.py = 0cd05fe6399030fc4932609cee3eee95
sickrage/search_providers/nzb/__init__.py = 2228e977ebea8966e27929f43e39cb67
sickrage/metadata_providers/kodi_12plus.py = a7c88d988d97ac25a5c14fb7004aff38
sickrage/metadata_providers/mede8er.py = 0c5dd3e61b0b009f4f5920a706aacb19
sickrage/metadata_providers/tivo.py = d690a863583e1e867c406228e192217f
sickrage/metadata_providers/kodi.py = 125bd1ecec4ceab086e38690117f1443
sickrage/metadata_providers/wdtv.py = af0f5efdc5cfab28ff91675f7715d64a
sickrage/metadata_providers/mediabrowser.py = 05150d6d2295c6bdfb443ad37486b4f9
sickrage/metadata_providers/__init__.py = ddb6dcf299351633628eb7ca1819f4a1
sickrage/metadata_providers/ps3.py = bc52287f697d2164b04d2fd9ab347bb1
sickrage/core/nzbSplitter.py = fed17a3a516e57d1ea9bfe63e446723b
sickrage/core/blackandwhitelist.py = 9d0a8e2aae2353a842306730c2690c2c
sickrage/core/classes.py = ca0d7c07b684b8fe22788346dc755fd8
sickrage/core/version_updater.py = d7d7405c680f18cf9672d8a6b1acdbd2
sickrage/core/ui.py = bc530df3dcdf73126f22b7c5719641be
sickrage/core/search.py = 5e354bf967b61ce27eed6b7ac7eeb84a
sickrage/core/auto_backup.py = 2dbdc017e5f9c5f25ca7d587b7454d96
sickrage/core/process_tv.py = 192c68108d5b5d1d0c84c7865209e21d
sickrage/core/traktapi.py = e30a23461b7e5d3af7619ad3e229bc40
sickrage/core/enums.py = b4194271791aabd8120fc16b2971b105
sickrage/core/imdb_popular.py = 59766fc80f9d41fcfa25cf81beab6c3a
sickrage/core/google_drive.py = 0129b53b8a649fa7c55bfe0c5ad11bdb
sickrage/core/upnp.py = 88671029e1f615c63c7745f7007f22eb
sickrage/core/scene_numbering.py = e517e5232d3b9ca186fe8b33578abd4b
sickrage/core/announcements.py = 6c3ed44e7ae50c281383ab5f278102c6
sickrage/core/__init__.py = 23c20908b4477ea1c24d6fe376aa13ee
sickrage/core/common.py = 8eca84658272c806858b105179285693
sickrage/core/api/exceptions.py = bdac7bcebad3d9ce2809f2d7e65810e0
sickrage/core/api/__init__.py = 21bc2ea4db99abf995e92fe56cba0a55
sickrage/core/exceptions/__init__.py = bb106687a1cb41cf0da10e125e0c82c7
sickrage/core/websocket/__init__.py = e5eddfe5d7ad4ca3c204c1d2d46857d1
sickrage/core/amqp/__init__.py = d64bec8a41b2f2d393b309eb2f33f5f0
sickrage/core/amqp/consumer.py = b2e4f47a0d1f119e5c3a71cd75ff6acf
sickrage/core/amqp/protos/server_certificate_v1_pb2.py = 4f7d5ac049e7472e5265e1e1335ff94f
sickrage/core/amqp/protos/network_timezone_v1_pb2.py = a8a4220a129924bc888f5316ae6f20ca
sickrage/core/amqp/protos/updates_v1_pb2.py = c4d1e1853249da497f0b59dbc44f67db
sickrage/core/amqp/protos/announcement_v1_pb2.py = c815479c7d07c1fd1edb2dee06a7aee3
sickrage/core/amqp/protos/search_provider_url_v1_pb2.py = 738197bd6a0e323bbba08fa11140c755
sickrage/core/media/fanart.py = 9cdfce700d3d6f0be1244867db7de70f
sickrage/core/media/banner.py = cf292898528a8031c0c2efa065c976f6
sickrage/core/media/network.py = 2df5f8040b90f5b4b0ec81896d2444ce
sickrage/core/media/__init__.py = a811d3d3805816476c17164275412208
sickrage/core/media/poster.py = 904d1ec6ccf97e7e6e859d56ba9b59ba
sickrage/core/media/util.py = 09ce682d5940bbf2776beeec77d0767c
sickrage/core/tv/__init__.py = d41d8cd98f00b204e9800998ecf8427e
sickrage/core/tv/episode/helpers.py = 12251c9697477624ac6a493c22553fd4
sickrage/core/tv/episode/__init__.py = e955f34e112961f0364c59f6cd6b687d
sickrage/core/tv/show/helpers.py = 9d887b91be03e52a2ff473312c59e077
sickrage/core/tv/show/history.py = 02a46fa4946cdf7b80915da916f25ca0
sickrage/core/tv/show/coming_episodes.py = 0d43711e559f1fbda75fc25b3485928f
sickrage/core/tv/show/__init__.py = dafbefc0e5660f3edc6be9c4e8de81bf
sickrage/core/processors/auto_postprocessor.py = 645f2b8ba9b8e9da3b1f73e98d44a4b7
sickrage/core/processors/failed_processor.py = c7d4a66b4b1e5c07a3376eb96de80e12
sickrage/core/processors/__init__.py = d41d8cd98f00b204e9800998ecf8427e
sickrage/core/processors/post_processor.py = 57b3a6a0423b22bb571a906ef023cb9d
sickrage/core/nameparser/validator.py = f40f97984b47eefa927fedcaaa314a6c
sickrage/core/nameparser/regexes.py = fbfb89e90f012a287266be8db0e2faf9
sickrage/core/nameparser/__init__.py = e164d40646cd722306eb61a144abe4e0
sickrage/core/searchers/trakt_searcher.py = 28493c9611e4f2e6b239fe77a7cf97a0
sickrage/core/searchers/daily_searcher.py = 433444d93fca22d05930524e0a550c91
sickrage/core/searchers/failed_snatch_searcher.py = 48125f4837802db70036dad8a1c0629f
sickrage/core/searchers/proper_searcher.py = 8176da80b50a517e7d444b5ed4bae3fe
sickrage/core/searchers/backlog_searcher.py = 7ca68c66a5fd1f9cfd447260e99a69d9
sickrage/core/searchers/subtitle_searcher.py = 64cac68c62879d5ff95ea238bcc900f8
sickrage/core/searchers/__init__.py = 096e3204587cd29aab63926bec3cd7f6
sickrage/core/auth/__init__.py = 77a7b80911e56cf91180789fd95e79d9
sickrage/core/updaters/tz_updater.py = 45ce45d6e44e5b8ab28bda9520200514
sickrage/core/updaters/rsscache_updater.py = 7317f7476248ebbaf0b35a491b52e2b5
sickrage/core/updaters/show_updater.py = 41d5d772e82d1ae872e7dbcbeee143e7
sickrage/core/updaters/__init__.py = d41d8cd98f00b204e9800998ecf8427e
sickrage/core/logger/__init__.py = d5a83f012ac6f0d9ababe2d6fb3ed370
sickrage/core/websession/__init__.py = 6d3d11bec0c0855e08a4c8f2cb6b759e
sickrage/core/databases/__init__.py = 4adab7c10011cd7b673b5556659e5b19
sickrage/core/databases/cache/__init__.py = da37d3eb7d09c694e3f2d1a2aa9772f6
sickrage/core/databases/cache/migrations/script.py.mako = 55bff267625bd1f0799d24848df6c3e8
sickrage/core/databases/cache/migrations/env.py = 5cdd195b4adf08a9eda769316ffcc57d
sickrage/core/databases/cache/migrations/versions/011_Bump_Version.py = 0ca85e1d08893befb97a838b08edf005
sickrage/core/databases/cache/migrations/versions/002_Remove_ID_Column_From_LastSearch_Table.py = 195ed064a4100c8dcb1fc5094e311751
sickrage/core/databases/cache/migrations/versions/005_Add_Announcements_Table.py = a345964e6fa8f668385c44c17f46e2f0
sickrage/core/databases/cache/migrations/versions/001_Add_Initial_Tables.py = 6416c418e06ad47834a3f6bdfe8ca4f1
sickrage/core/databases/cache/migrations/versions/009_Add_SeriesProviderID_Column_To_Providers_Table.py = 183869e4d40eb40b1b77512899516e35
sickrage/core/databases/cache/migrations/versions/007_Add_Token_Type_Column_To_OAuth2Token_Table.py = 122b771b45c28a889c97f93ac7d2a5ce
sickrage/core/databases/cache/migrations/versions/003_Rename_IndexerID_To_SeriesID_On_Provider_Table.py = ad113c83b459f0ebf82fefaaf6750f84
sickrage/core/databases/cache/migrations/versions/004_Add_OAuth2Token_Table.py = caca51f0c9069e59b9e4b430a842ddb7
sickrage/core/databases/cache/migrations/versions/006_Add_Session_State_Column_To_OAuth2Token_Table.py = 1ec44e448315a95b5ca825c13f9326e5
sickrage/core/databases/cache/migrations/versions/008_Drop_QuickSearch_Tables.py = cf262ebb9ac197656a2d68af7b126714
sickrage/core/databases/cache/migrations/versions/010_Remove_OAuth2Token_Table.py = f69d7de4bd59f5c92a3ffbe8a41d78e2
sickrage/core/databases/main/schemas.py = 7264494b24575ea1dcab57f0b3edc01d
sickrage/core/databases/main/__init__.py = dfb9975984b7f5adef7597bd136963aa
sickrage/core/databases/main/migrations/script.py.mako = 55bff267625bd1f0799d24848df6c3e8
sickrage/core/databases/main/migrations/env.py = 5cdd195b4adf08a9eda769316ffcc57d
sickrage/core/databases/main/migrations/versions/005_Rename_Columns_On_IMDbInfo_Table.py = bd5b90f2fa31ead91f8be78404768a2e
sickrage/core/databases/main/migrations/versions/023_Bump_Version.py = 2c33dca3cf846ab319fdf7a3116fe809
sickrage/core/databases/main/migrations/versions/021_Upgrade_To_SiCKRAGE_v10.py = 085cf77d626353e391400eaa54d837ac
sickrage/core/databases/main/migrations/versions/009_Convert_Date_Column_To_DateTime_Type_On_History_Table.py = e159d4be5a9ae550b2ca71230c2fc7a1
sickrage/core/databases/main/migrations/versions/017_Convert_SearchFormat_Column_To_Enum_Type_On_TVShow_Table.py = debac47d39bb7ba0884495175ce74591
sickrage/core/databases/main/migrations/versions/019_Convert_Timestamp_Integer_Columns_To_DateTime_Type_On_TVShow_Table.py = 68a62a5fa7512404104db8d6fe37e915
sickrage/core/databases/main/migrations/versions/018_Convert_Timestamp_Integer_Columns_To_DateTime_Type_On_TVEpisode_Table.py = 9fe241e2a03db8133f3ab375144c79ee
sickrage/core/databases/main/migrations/versions/001_Add_Initial_Tables.py = 6416c418e06ad47834a3f6bdfe8ca4f1
sickrage/core/databases/main/migrations/versions/014_Add_Last_XEM_Refresh_Column_To_TVShows_Table.py = 08b3a05209d019db448e05e877ee8af3
sickrage/core/databases/main/migrations/versions/022_Convert_Language_Codes_To_ISO6393_On_TVShow_Table.py = ed9eed9138a010004ed44f8470de583b
sickrage/core/databases/main/migrations/versions/011_Add_Scene_Exceptions_Column_To_TVShow_Table.py = e51bd8a97d4ada356b615c0a5c24e77e
sickrage/core/databases/main/migrations/versions/004_Rename_Columns_On_TVShow_Table.py = 347e30546823c3f7e0d4577b72a97ec7
sickrage/core/databases/main/migrations/versions/013_Add_Scene_Column_To_TVShow_Table.py = f97875eebaa1de29b5043243d7564b88
sickrage/core/databases/main/migrations/versions/010_Add_Release_Group_Column_To_History_Table.py = 1f880de39cefced74265821002222e4d
sickrage/core/databases/main/migrations/versions/012_Add_Search_Format_Column_To_TVShow_Table.py = 1dcfe8e2df80e134eecb6be25844c8ff
sickrage/core/databases/main/migrations/versions/007_Convert_Airdate_Column_To_Date_Type_On_TVEpisode_Table.py = 8a7c62ae9e802474c01d9db38c964bb7
sickrage/core/databases/main/migrations/versions/008_Convert_Date_Column_To_DateTime_Type_On_FailedSnatchHistory_Table.py = 2705761cf26350cf21237a0afe8cad02
sickrage/core/databases/main/migrations/versions/015_Add_XEM_Numbering_To_TVEpisodes_Table.py = c5d326c3750d1ee0cd518481b024f855
sickrage/core/databases/main/migrations/versions/020_Convert_Timestamp_Integer_Columns_To_DateTime_Type_On_ImdbInfo_Table.py = 7b28fd15eb59c96d19ae29e0cbc254e8
sickrage/core/databases/main/migrations/versions/003_Add_Last_Proper_Search_Column_To_TVShow_Table.py = e803eff26895483a07d0926614e32eac
sickrage/core/databases/main/migrations/versions/002_Add_Last_Backlog_Search_Column_To_TVShow_Table.py = 130fca353214b471cc09748dee685951
sickrage/core/databases/main/migrations/versions/016_Merge_Scene_Numbering_Table_With_TVEpisodes_Table.py = 0df11139fa75f642a9f4c893d08f6a69
sickrage/core/databases/main/migrations/versions/006_Rename_Columns_On_TVEpisode_Table.py = 4f5da87896901f7052734388ce5a28cb
sickrage/core/databases/config/schemas.py = f81fcc28e52cef56d6aa9969286c3152
sickrage/core/databases/config/__init__.py = cec594ee3743e6dc8bbefffa4ebf3c2e
sickrage/core/databases/config/migrations/script.py.mako = 55bff267625bd1f0799d24848df6c3e8
sickrage/core/databases/config/migrations/env.py = 5cdd195b4adf08a9eda769316ffcc57d
sickrage/core/databases/config/migrations/versions/006_Bump_Version.py = e8f0c6bb0cc8c9a0deabd7a80ab94e95
sickrage/core/databases/config/migrations/versions/001_Add_Initial_Tables.py = 6416c418e06ad47834a3f6bdfe8ca4f1
sickrage/core/databases/config/migrations/versions/009_Add_AutoBackup_Columns_To_General_Table.py = a1597b8b50468b80a4bd4ea5f645357c
sickrage/core/databases/config/migrations/versions/008_Add_Update_Video_Metadata_Column_To_General_Table.py = 66b27a2094fb41f1880175c18e409bec
sickrage/core/databases/config/migrations/versions/003_Remove_Search_Providers_Newznab_Key_Column.py = dabd4dfa4f8f8deea32633da0139732d
sickrage/core/databases/config/migrations/versions/007_Convert_NMA_Priority_Column_To_Integer.py = 31fc3ddd797d5470c5bd3ffa14ae52ef
sickrage/core/databases/config/migrations/versions/005_Convert_Default_Series_Provider_Language_Code_To_ISO6393_In_General_Table.py = 97ef1485dc2b39fb74524dc0a38b35bb
sickrage/core/databases/config/migrations/versions/004_Add_SSO_API_Key_Column_To_General_Table.py = 0c3d2ac9f38cd91f716a471dcd45ec51
sickrage/core/databases/config/migrations/versions/002_Remove_Web_Host_Column.py = 7d13d30620ad949f94320af0ae2625c6
sickrage/core/helpers/encryption.py = 8a74f080644fcfe249e56e8a31c2f62e
sickrage/core/helpers/srdatetime.py = 1ec93b21792f45dbcd8a574c02db4d34
sickrage/core/helpers/browser.py = 6da2ce70dea2674b01543ad1a4f216b2
sickrage/core/helpers/show_names.py = 8a1d64050ccd03f8395e78da3fc60fef
sickrage/core/helpers/metadata.py = 65108aa990c8bb0218cde3e0834e715c
sickrage/core/helpers/__init__.py = cd1686a52f643a98740216ce5f47a0c1
sickrage/core/helpers/anidb.py = 69f80b887bc822499ecefbd5ec52ef5c
sickrage/core/caches/tv_cache.py = f8ce584c2fdd44681b6f79b662fdcfbe
sickrage/core/caches/name_cache.py = 8cceca1983838af2e581c6187912b2cc
sickrage/core/caches/__init__.py = bf0bdb641ddd7af015537ca503e49977
sickrage/core/caches/image_cache.py = f7395f1da926716ac5aaab7de0a2d00d
sickrage/core/config/helpers.py = f888b4bcaeec058a4ec10f96b36ec696
sickrage/core/config/__init__.py = f110b2063d34aaf7bd6d1f7954c967d4
sickrage/core/webserver/helpers.py = 0d343b8b2638308bbb11af6d22784e75
sickrage/core/webserver/__init__.py = 2cf4a790848de7a7dbf8c83cc5e0cb00
sickrage/core/webserver/static/fonts/fa-regular-400.svg = e75dfd904d366a2560c63c23cfc98ef8
sickrage/core/webserver/static/fonts/fa-solid-900.eot = 89bd2e38475e441a5cd70f663f921d61
sickrage/core/webserver/static/fonts/fa-brands-400.woff2 = cac68c831145804808381a7032fdc7c2
sickrage/core/webserver/static/fonts/fa-brands-400.ttf = 085b1dd8427dbeff10bd55410915a3f6
sickrage/core/webserver/static/fonts/fa-solid-900.woff = ee09ad7553b8ad3d81150d609d5341a0
sickrage/core/webserver/static/fonts/fa-regular-400.woff = 05b53beb21e3ef13d28244545977152d
sickrage/core/webserver/static/fonts/fa-regular-400.woff2 = 3a3398a6ef60fc64eacf45665958342e
sickrage/core/webserver/static/fonts/fa-brands-400.svg = ccfdb9dc442be0c629d331e94497428b
sickrage/core/webserver/static/fonts/fa-solid-900.ttf = 781e85bb50c8e8301c30de56b31b1f04
sickrage/core/webserver/static/fonts/fa-brands-400.woff = dc0bd022735ed218df547742a1b2f172
sickrage/core/webserver/static/fonts/fa-solid-900.svg = 03ba7cb710104df27f1c9c46d64bee4e
sickrage/core/webserver/static/fonts/fa-brands-400.eot = 0fabb6606be4c45acfeedd115d0caca4
sickrage/core/webserver/static/fonts/fa-regular-400.ttf = 1a78af4105d4d56e6c34f76dc70bf1bc
sickrage/core/webserver/static/fonts/fa-regular-400.eot = ad3a7c0d77e09602f4ab73db3660ffd8
sickrage/core/webserver/static/fonts/fa-solid-900.woff2 = c500da19d776384ba69573ae6fe274e7
sickrage/core/webserver/static/images/sickrage-subtitles.png = 347e40b994441f3434cccfec22c6f85f
sickrage/core/webserver/static/images/logo-badge.png = 920d5019038a2d684fe95f05a9872158
sickrage/core/webserver/static/images/poster-thumb.png = b788e8476ff0a2d3dfca0eb1d31bab58
sickrage/core/webserver/static/images/sickrage-core.png = 70bfd38925d288fdc42f92e9aa13d394
sickrage/core/webserver/static/images/ui-icons_cc0000_256x240.png = 0de3b51742ed3ac61435875bccd8973b
sickrage/core/webserver/static/images/bootstrap-formhelpers-googlefonts.png = 555a64106e7f136f0c734ef6b3e93d61
sickrage/core/webserver/static/images/banner.png = 56232ad7614dbd0dbbd478d7f5179cda
sickrage/core/webserver/static/images/sickrage-providers.png = d41d8cd98f00b204e9800998ecf8427e
sickrage/core/webserver/static/images/favicon.png = 354962cc3967175b29b3e6dd5f5a840a
sickrage/core/webserver/static/images/ui-icons_ffffff_256x240.png = bf27228a7d3957983584fa7698121ea1
sickrage/core/webserver/static/images/sickrage-notifiers.png = 5940b800460a818bf75869a2ca2db283
sickrage/core/webserver/static/images/sickrage-series-providers.png = 25e08354c03274224c10022a807b72a9
sickrage/core/webserver/static/images/sickrage-network.png = 8d1362d1cba595fc3facb3d166cf24e0
sickrage/core/webserver/static/images/poster.png = 7f6012b2eb0cd675e0b54800ace4f4a2
sickrage/core/webserver/static/images/ui-icons_444444_256x240.png = a4c733ec4baef9ad3896d4e34a8a5448
sickrage/core/webserver/static/images/ui-icons_777620_256x240.png = 208a290102a4ada58a04de354a1354d7
sickrage/core/webserver/static/images/bootstrap-formhelpers-currencies.flags.png = ce982214016d2940488c2c98e0929a41
sickrage/core/webserver/static/images/ui-icons_777777_256x240.png = 73a1fd052c9d84c0ee0bea3ee85892ed
sickrage/core/webserver/static/images/sickrage-flags.png = c9056bffffebdc8ad9fc96d12bdbf33f
sickrage/core/webserver/static/images/banner-thumb.png = 2fd679208852752a7397693426261dec
sickrage/core/webserver/static/images/favicon.ico = 6627b9f36868075dd46e5886d3a55a8c
sickrage/core/webserver/static/images/bootstrap-formhelpers-countries.flags.png = 8404ee935503dfec7a38ffe093f73e05
sickrage/core/webserver/static/images/ui-icons_555555_256x240.png = 971364734f3b603e5d363a2634898b42
sickrage/core/webserver/static/images/sickrage-notification-providers.png = 5940b800460a818bf75869a2ca2db283
sickrage/core/webserver/static/images/trakt-poster.png = 422af16299678b757bcc7b3135c2f77a
sickrage/core/webserver/static/images/logo.png = 538f988fc423c21e1447018e4b699b5a
sickrage/core/webserver/static/images/sickrage-search-providers.png = 3e8794148b43046b12e72c683e233708
sickrage/core/webserver/static/images/backdrops/config.jpg = ddbe8915317f7860d91beda3de19f4e7
sickrage/core/webserver/static/images/backdrops/schedule.jpg = 0c0e5f4dcee42bfcfb73de100f1d3015
sickrage/core/webserver/static/images/backdrops/history.jpg = b4911bfe3ec57a894b5a16fa1ab479cf
sickrage/core/webserver/static/images/backdrops/manage.jpg = 2e49098c0ed9aacf6029b67c5af1f109
sickrage/core/webserver/static/images/backdrops/home.jpg = 804dfc976638bbf45df310a3627e2d5c
sickrage/core/webserver/static/images/backdrops/addshows.jpg = 7f3e186790208b63dadda09d6b91d334
sickrage/core/webserver/static/css/core.min.css = 8952d8577e8cf93dafa16eeeed7e178d
sickrage/core/webserver/static/js/core.min.js = 38b6ef5df49990b5ad85b6cb307bf1d4
sickrage/core/webserver/static/js/core.js.map = 5afe2cad8e9748b85459a3a80beecd23
sickrage/core/webserver/handlers/web_file_browser.py = fd7ea59001053b333cd56960181d4550
sickrage/core/webserver/handlers/root.py = be47a31ef1b27e6c8ca4abe9d5c4c3f8
sickrage/core/webserver/handlers/not_found.py = 3b7253c2d4d323cbb0dc6828d87c8d2c
sickrage/core/webserver/handlers/base.py = 0242c4eef3dc3c43feb6ac67f1ad1ac5
sickrage/core/webserver/handlers/logs.py = c0e649db7efc0168a8dcbea429878deb
sickrage/core/webserver/handlers/account.py = 1cf412e7a3427fa49205f0478adb657f
sickrage/core/webserver/handlers/google_drive.py = 98fde470e65096ec71a8e3f1cce2bd44
sickrage/core/webserver/handlers/changelog.py = 74407bee7cd98416432124fbb2a9c529
sickrage/core/webserver/handlers/history.py = 34961ffbbb07803515ded9626c7f853a
sickrage/core/webserver/handlers/calendar.py = 8053d4d70a574a54d4bb9a0ad88f9f4e
sickrage/core/webserver/handlers/announcements.py = cca0415f047c367e5b41c0fed6a24dbf
sickrage/core/webserver/handlers/login.py = dc8a99c4182abcff03cdced98310c691
sickrage/core/webserver/handlers/__init__.py = 4e94a1192bc45368b8cc3cd5f6d1debc
sickrage/core/webserver/handlers/logout.py = 29535aff16270bf23017c7b8bf09d644
sickrage/core/webserver/handlers/api/schemas.py = 7fcfd3dee63378ba5bd8fcbaebbf49ef
sickrage/core/webserver/handlers/api/__init__.py = a57913795cb35866e8edec8f61ab4747
sickrage/core/webserver/handlers/api/v1/__init__.py = 97d37e3898f6602c069a3a0cc573ff2e
sickrage/core/webserver/handlers/api/v2/__init__.py = 331c145796355d52ae1818bf9fd69ced
sickrage/core/webserver/handlers/api/v2/postprocess/schemas.py = 994d368e0a2321b8311700d613695563
sickrage/core/webserver/handlers/api/v2/postprocess/__init__.py = 0c2bf1754d86ee7c2b4751d94bf8d443
sickrage/core/webserver/handlers/api/v2/episode/schemas.py = 014e84083401e6b05a9626cb29bd8467
sickrage/core/webserver/handlers/api/v2/episode/__init__.py = accce54f7387f1a65befc8121d6862fa
sickrage/core/webserver/handlers/api/v2/series_provider/schemas.py = 014e84083401e6b05a9626cb29bd8467
sickrage/core/webserver/handlers/api/v2/series_provider/__init__.py = 96d4f6bdd84c81c75e61a6ad06232a4c
sickrage/core/webserver/handlers/api/v2/history/schemas.py = 014e84083401e6b05a9626cb29bd8467
sickrage/core/webserver/handlers/api/v2/history/__init__.py = 96ec5aabeb125e7340012655ccb499c7
sickrage/core/webserver/handlers/api/v2/schedule/schemas.py = 4af02a112f828040cbb1cf34ad03fdd5
sickrage/core/webserver/handlers/api/v2/schedule/__init__.py = ee7f141e9f81cfd1d63bf1e1d5e10749
sickrage/core/webserver/handlers/api/v2/file_browser/schemas.py = 014e84083401e6b05a9626cb29bd8467
sickrage/core/webserver/handlers/api/v2/file_browser/__init__.py = 5e348f6f96a80a98dca3ae2b9151ac33
sickrage/core/webserver/handlers/api/v2/config/schemas.py = 014e84083401e6b05a9626cb29bd8467
sickrage/core/webserver/handlers/api/v2/config/__init__.py = 6df0e54610ef10b3d9eb1bd3ec56176c
sickrage/core/webserver/handlers/api/v2/series/schemas.py = b5159b40ee6d67aa04a85de7c7810284
sickrage/core/webserver/handlers/api/v2/series/__init__.py = 591df51c8945e346ac9532cfa0215ba9
sickrage/core/webserver/handlers/manage/queues.py = f92d4a8b34b1872e529886f4aa80ed08
sickrage/core/webserver/handlers/manage/__init__.py = 6b79f83afdd5565b06310e22245f882b
sickrage/core/webserver/handlers/home/postprocess.py = bd1ea821bd162300af4b5bf27c5aba94
sickrage/core/webserver/handlers/home/add_shows.py = f804dd91bfff99cc079f14f83e2604f3
sickrage/core/webserver/handlers/home/__init__.py = 5201c9dd146de3dfe982695cba400cdd
sickrage/core/webserver/handlers/config/subtitles.py = 73b0155c03e43a895e3456a83f6f5558
sickrage/core/webserver/handlers/config/providers.py = 0984dfd7f6d3abe0c71224cb98b6c128
sickrage/core/webserver/handlers/config/quality_settings.py = 6a2849c97b8635d46a92b758ba641428
sickrage/core/webserver/handlers/config/search.py = 6ced2a39316938481d9d5086184bb3c5
sickrage/core/webserver/handlers/config/notifications.py = 88ee26540e55fa1aa65de84ed7d40fc5
sickrage/core/webserver/handlers/config/backup_restore.py = 30dbb6795e0624fc28afce2c61cfe77d
sickrage/core/webserver/handlers/config/postprocessing.py = 85f89d663c651279cf9b589d8934431a
sickrage/core/webserver/handlers/config/general.py = da126ab24f955a9ec9f4e201da177bf7
sickrage/core/webserver/handlers/config/__init__.py = 1b9eeca6d49289e7c36bf369450e459c
sickrage/core/webserver/handlers/config/anime.py = b30c5a43317e9bc2fde98493364391f1
sickrage/core/webserver/views/history.mako = a90a54341918b398eb652d186a636952
sickrage/core/webserver/views/schedule.mako = 1492940accef5afe80d9cbd14be1c078
sickrage/core/webserver/views/announcements.mako = d5902b3926cc0d02cc1329676d8a9e1b
sickrage/core/webserver/views/login_failed.mako = 5684d10edff37970a2285d7d5bb815eb
sickrage/core/webserver/views/api_builder.mako = c4fdcfda5661806f2df9e9b66af5c692
sickrage/core/webserver/views/login.mako = 3f6c8e8325928539d6bb70a77b378116
sickrage/core/webserver/views/generic_message.mako = 20ba53fc129c1b69d5b8ccc960233757
sickrage/core/webserver/views/includes/modals.mako = c790f223e9420d53d19c3e544688dcdc
sickrage/core/webserver/views/includes/root_dirs.mako = a6c90b2bd53d3a773f2d705e090fedec
sickrage/core/webserver/views/includes/quality_defaults.mako = a44bb0e0d5de92ac582abced46796ead
sickrage/core/webserver/views/includes/blackwhitelist.mako = fba8c39fd140cb1e897dfa259060655f
sickrage/core/webserver/views/includes/add_show_options.mako = 4491fad6a224e365251f24c581213dfd
sickrage/core/webserver/views/includes/quality_chooser.mako = aedf4fa8d265e899ebb040e6a0a8e3e5
sickrage/core/webserver/views/manage/mass_update.mako = d976337072d227c5b461eb7649d30ff5
sickrage/core/webserver/views/manage/queues.mako = 98fc8566c50c3e9df596664996be4ae1
sickrage/core/webserver/views/manage/mass_edit.mako = 474e2ce2ade7f877c987f6c0ff5510bd
sickrage/core/webserver/views/manage/backlog_overview.mako = dbcc805fc3c5457851cd5e72b73a63d8
sickrage/core/webserver/views/manage/failed_downloads.mako = 7f4b1084557d45fb04546f39fb5e1a9b
sickrage/core/webserver/views/manage/torrents.mako = de68a5f927f912000fafd72ae4b7ea81
sickrage/core/webserver/views/manage/subtitles_missed.mako = 51a48edfe52e59aafef757792862a592
sickrage/core/webserver/views/manage/episode_statuses.mako = 5eebfd975603aaa45ec4a3b645a243d5
sickrage/core/webserver/views/layouts/main.mako = 58e4866571c5f4875f924bb0a61f45d4
sickrage/core/webserver/views/layouts/config.mako = 01c13d7c7511d93384f9ffb35932a218
sickrage/core/webserver/views/errors/500.mako = dde078ba1d942aedf9e94afca17ce314
sickrage/core/webserver/views/home/test_renaming.mako = d0295056378d687b18c7050204f73ee3
sickrage/core/webserver/views/home/mass_add_table.mako = f5ddb3d4d96a536f5f58fc5c4daeb104
sickrage/core/webserver/views/home/add_existing_shows.mako = 5c558d6612c1610ba7e71db4f8dd5c2e
sickrage/core/webserver/views/home/display_show.mako = 586f8316f7d818de5346a5b74e2b7ccf
sickrage/core/webserver/views/home/index.mako = cd079065ad7d77c9eb6dfb7d26d4daba
sickrage/core/webserver/views/home/new_show.mako = df46b30a58792d3fe63cd6b7389e36cc
sickrage/core/webserver/views/home/edit_show.mako = 074b1e84284d763085c792a306771b72
sickrage/core/webserver/views/home/trakt_shows.mako = 09a95e4badea76e427946773a6cfa650
sickrage/core/webserver/views/home/provider_status.mako = 098f2cede3a37989b97061b6d55678fc
sickrage/core/webserver/views/home/server_status.mako = 35c73890074a64a60f2c761d9503a138
sickrage/core/webserver/views/home/restart.mako = 2cb040bd0c69b9a971c7d36f62dd9609
sickrage/core/webserver/views/home/add_shows.mako = 388debd9471602a25e302a6fb202f587
sickrage/core/webserver/views/home/imdb_shows.mako = 63b177441ccc7e360588e2361c0acd5b
sickrage/core/webserver/views/home/postprocess.mako = a04d644e06e68be64df1717898de3bdf
sickrage/core/webserver/views/logs/errors.mako = 5a27833f9ec45e27335e0870f8b6500b
sickrage/core/webserver/views/logs/view.mako = 9e19653304870852a7b0d7a25d1a3187
sickrage/core/webserver/views/config/backup_restore.mako = 1ecf44ded38a1b618af5e367c27c1415
sickrage/core/webserver/views/config/notifications.mako = 929ec6cdc94d34ce4906b413e8bfa105
sickrage/core/webserver/views/config/search.mako = c42821d0e00aaccf078049751d0e2792
sickrage/core/webserver/views/config/general.mako = b383d68bdc306d74f11bd27f891b571e
sickrage/core/webserver/views/config/index.mako = 1409d0d595d2fdb45350f83b1c858288
sickrage/core/webserver/views/config/postprocessing.mako = e8281bd34c740300afd22e467a93867c
sickrage/core/webserver/views/config/subtitles.mako = 2bbf1cf91683bf5f8e50cdfad7708ad3
sickrage/core/webserver/views/config/quality_settings.mako = c4fd4793b475aa8aafdaac0444390a43
sickrage/core/webserver/views/config/providers.mako = 2b4d33c823914336b38d6029e00f80ea
sickrage/core/webserver/views/config/anime.mako = e8f8372ef2c877374d25ca43060d6f69
sickrage/core/queues/search.py = 0b53c8a4e726e9fcbd3243db68b39ab3
sickrage/core/queues/postprocessor.py = b2bcd7642060906c2c21d554d114b9ee
sickrage/core/queues/__init__.py = c136baa75298e277395a6d0b60e7404d
sickrage/core/queues/show.py = 5d78f1349528a607cc96c020c80cf526
sickrage/notification_providers/synology.py = bdb3f339ae68cdae4a20c69a2515d641
sickrage/notification_providers/telegram.py = 2d0c2cf662c52c804eaeb58f2f02b5df
sickrage/notification_providers/pushalot.py = 8d70db69f721234fbe989f9d61094473
sickrage/notification_providers/libnotify.py = 36f35e6ea22d9abbefd94916eb60507b
sickrage/notification_providers/discord.py = 9f26b9d8213c90f358919717aa7f7607
sickrage/notification_providers/freemobile.py = 33602ca8806a464a13f3138eadea75e2
sickrage/notification_providers/synoindex.py = a31b37344937342b871d61334a89d0e2
sickrage/notification_providers/pushbullet.py = e6da13a362da7ca55791cd99f0016d18
sickrage/notification_providers/prowl.py = 90fd71420ba010b7e043bcaff75636b7
sickrage/notification_providers/nmjv2.py = 45e8776cba89bac3dae261dee5b30f2c
sickrage/notification_providers/twilio_notifer.py = c7c143030fa866109c23b32823b26255
sickrage/notification_providers/pytivo.py = 7a1147a12c6044715576220a8c615afa
sickrage/notification_providers/alexa.py = 9dd602eb7cd2444870dc773c5dae93fc
sickrage/notification_providers/kodi.py = 94ee2d35496f1edffea2a5f2c5030b28
sickrage/notification_providers/tweet.py = 9bf62b3de7d9274ce79c750b430405df
sickrage/notification_providers/trakt.py = 7bc4cae9a78be9cf1de56d7529fa6bd2
sickrage/notification_providers/boxcar2.py = 8745e7663b333b9cc3271cd5e8ce432e
sickrage/notification_providers/emailnotify.py = e73648c83ee29abbfc8e9ecd3a00130f
sickrage/notification_providers/join.py = c7ac1a389c15d2b761ed8fbeb97c05d7
sickrage/notification_providers/nmj.py = 16b1b008aa8200c0ad3eb065b6137b4b
sickrage/notification_providers/slack.py = f10bec22fd58916bdd3f497200fa59ea
sickrage/notification_providers/growl.py = a0414823524591e4698adb546f1d351e
sickrage/notification_providers/nma.py = eb175b1646649fee937962e2d5da1486
sickrage/notification_providers/__init__.py = 566ab4ebcd356e4384cdf75e6f0aa375
sickrage/notification_providers/plex.py = d5b285b2c351e7807cc495477465d516
sickrage/notification_providers/emby.py = d556957c901e2d66ebea793fa4d7b90e
sickrage/notification_providers/pushover.py = 82f4deeae4c78ad24cc5520d3d821e48
sickrage/clients/__init__.py = 163d6d33cb04526ae0895632e69ad265
sickrage/clients/torrent/putio.py = e3635cb458be1bd9e6dbdf10ceaa2bd4
sickrage/clients/torrent/deluged.py = f7291242ab46a4668c0b54cd7821dff0
sickrage/clients/torrent/deluge.py = f46c2b151a1a1efca459507176079561
sickrage/clients/torrent/qbittorrent.py = a71cb0f96ecd6692efa489dfcbbff409
sickrage/clients/torrent/download_station.py = 04fa661783d573af093f9d7451410511
sickrage/clients/torrent/utorrent.py = b18de6ea4d6e427714f9c059882d83da
sickrage/clients/torrent/transmission.py = 8843ec4fdb29a473bcdbbc0d5fa87574
sickrage/clients/torrent/rtorrent.py = 8a0b8c41657a70e53606098339235fa3
sickrage/clients/torrent/__init__.py = 014e84083401e6b05a9626cb29bd8467
sickrage/clients/torrent/mlnet.py = 0e73345f3516a57eeaf9dea40ecbbddc
sickrage/clients/nzb/sabnzbd.py = f76666e47017abaf366f4a3e8b71c47b
sickrage/clients/nzb/download_station.py = 97c5e65dda67818a767878adcbf85e0e
sickrage/clients/nzb/nzbget.py = 2a23083d4915fed22c73f4966588cac8
sickrage/clients/nzb/__init__.py = 4e94a1192bc45368b8cc3cd5f6d1debc
================================================
FILE: sickrage/clients/__init__.py
================================================
# Author: echel0n
# URL: https://sickrage.ca
#
# This file is part of SiCKRAGE.
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
import re
import time
import bencodepy
from base64 import b16encode, b32decode
from hashlib import sha1
import sickrage
from sickrage.core.websession import WebSession
from sickrage.search_providers import SearchProviderType
_clients = {
'utorrent': 'uTorrentAPI',
'transmission': 'TransmissionAPI',
'deluge': 'DelugeAPI',
'deluged': 'DelugeDAPI',
'download_station': 'DownloadStationAPI',
'rtorrent': 'rTorrentAPI',
'qbittorrent': 'QBittorrentAPI',
'mlnet': 'mlnetAPI',
'putio': 'PutioAPI',
}
class GenericClient(object):
def __init__(self, name, host=None, username=None, password=None):
self.name = name
self.username = sickrage.app.config.torrent.username if not username else username
self.password = sickrage.app.config.torrent.password if not password else password
self.host = sickrage.app.config.torrent.host if not host else host
self.rpcurl = sickrage.app.config.torrent.rpc_url
self.url = None
self.auth = None
self.last_time = time.time()
self.session = WebSession(cache=False)
self._response = None
@property
def response(self):
return self._response
@response.setter
def response(self, value):
self._response = value
def _request(self, method='get', params=None, data=None, *args, **kwargs):
if time.time() > self.last_time + 1800 or not self.auth:
self.last_time = time.time()
self._get_auth()
sickrage.app.log.debug(
'{name}: Requested a {method} connection to {url} with'
' params: {params} Data: {data}'.format(
name=self.name,
method=method.upper(),
url=self.url,
params=params,
data=str(data)[0:99] + '...' if len(str(data)) > 102 else str(data)
)
)
if not self.auth:
sickrage.app.log.warning(self.name + ': Authentication Failed')
return False
self.response = self.session.request(method.upper(), self.url,
params=params, data=data, auth=(self.username, self.password), timeout=120, verify=False, *args, **kwargs)
if not self.response or not self.response.text:
return False
sickrage.app.log.debug('{name}: Response to {method} request is {response}'.format(
name=self.name,
method=method.upper(),
response=self.response.text
))
return True
def _get_auth(self):
"""
This should be overridden and should return the auth_id needed for the client
"""
return None
def test_authentication(self):
# verify valid url
self.response = self.session.get(self.url or self.host, timeout=120, verify=False)
if self.response is None:
return False, 'Error: Unable to connect to ' + self.name
# verify auth
if self._get_auth():
return True, 'Success: Connected and Authenticated'
return False, 'Error: Unable to get ' + self.name + ' Authentication, check your config!'
class TorrentClient(GenericClient):
def _add_torrent_uri(self, result):
"""
This should be overridden should return the True/False from the client
when a torrent is added via url (magnet or .torrent link)
"""
return False
def _add_torrent_file(self, result):
"""
This should be overridden should return the True/False from the client
when a torrent is added via result.content (only .torrent file)
"""
return False
def _set_torrent_label(self, result):
"""
This should be overridden should return the True/False from the client
when a torrent is set with label
"""
return True
def _set_torrent_ratio(self, result):
"""
This should be overridden should return the True/False from the client
when a torrent is set with ratio
"""
return True
def _set_torrent_seed_time(self, result):
"""
This should be overridden should return the True/False from the client
when a torrent is set with a seed time
"""
return True
def _set_torrent_priority(self, result):
"""
This should be overriden should return the True/False from the client
when a torrent is set with result.priority (-1 = low, 0 = normal, 1 = high)
"""
return True
def _set_torrent_path(self, torrent_path):
"""
This should be overridden should return the True/False from the client
when a torrent is set with path
"""
return True
def _set_torrent_pause(self, result):
"""
This should be overridden should return the True/False from the client
when a torrent is set with pause
"""
return True
@staticmethod
def _get_torrent_hash(result):
if result.url.startswith('magnet'):
result.hash = re.findall(r'urn:btih:([\w]{32,40})', result.url)[0]
if len(result.hash) == 32:
result.hash = b16encode(b32decode(result.hash)).lower()
else:
if not result.content:
sickrage.app.log.warning('Torrent without content')
raise Exception('Torrent without content')
try:
torrent_bdecode = bencodepy.decode(result.content)
except bencodepy.exceptions.BencodeDecodeError:
sickrage.app.log.warning('Unable to bdecode torrent')
sickrage.app.log.debug('Torrent bencoded data: %r' % result.content)
raise
try:
info = torrent_bdecode["info"]
except Exception:
sickrage.app.log.warning('Unable to find info field in torrent')
raise
result.hash = sha1(bencodepy.encode(info)).hexdigest()
return result
def send_torrent(self, result):
r_code = False
sickrage.app.log.debug('Calling ' + self.name + ' Client')
try:
if not self._get_auth():
sickrage.app.log.warning(self.name + ': Authentication Failed')
return r_code
# Sets per provider seed ratio
result.ratio = result.provider.seed_ratio
# lazy fix for now, I'm sure we already do this somewhere else too
result = self._get_torrent_hash(result)
# convert to magnetic url if result has info hash and is not a private provider
if sickrage.app.config.general.torrent_file_to_magnet:
if result.hash and not result.provider.private and not result.url.startswith('magnet'):
result.url = "magnet:?xt=urn:btih:{}".format(result.hash)
if result.url.startswith('magnet'):
r_code = self._add_torrent_uri(result)
else:
r_code = self._add_torrent_file(result)
if not r_code:
sickrage.app.log.warning(self.name + ': Unable to send Torrent')
return False
if not self._set_torrent_pause(result):
sickrage.app.log.warning(self.name + ': Unable to set the pause for Torrent')
if not self._set_torrent_label(result):
sickrage.app.log.warning(self.name + ': Unable to set the label for Torrent')
if not self._set_torrent_ratio(result):
sickrage.app.log.warning(self.name + ': Unable to set the ratio for Torrent')
if not self._set_torrent_seed_time(result):
sickrage.app.log.warning(self.name + ': Unable to set the seed time for Torrent')
if not self._set_torrent_path(result):
sickrage.app.log.warning(self.name + ': Unable to set the path for Torrent')
if result.priority != 0 and not self._set_torrent_priority(result):
sickrage.app.log.warning(self.name + ': Unable to set priority for Torrent')
except Exception as e:
sickrage.app.log.warning(self.name + ': Failed Sending Torrent')
sickrage.app.log.debug(self.name + ': Exception raised when sending torrent: {}. Error: {}'.format(result, e))
return r_code
return r_code
class NZBClient(GenericClient):
def _add_nzb_uri(self, result):
"""
This should be overridden should return the True/False from the client
when a torrent is added via url (magnet or .torrent link)
"""
return False
def _add_nzb_file(self, result):
"""
This should be overridden should return the True/False from the client
when a torrent is added via result.content (only .torrent file)
"""
return False
def send_nzb(self, result):
if result.provider_type == SearchProviderType.NZB:
return self._add_nzb_uri(result)
elif result.provider_type == SearchProviderType.NZBDATA:
return self._add_nzb_file(result)
def get_client_module(name, client_type):
return __import__("{}.{}.{}".format(__name__, client_type, name.lower()), fromlist=list(_clients.keys()))
def get_client_instance(name, client_type):
return getattr(get_client_module(name, client_type), _clients[name])
================================================
FILE: sickrage/clients/nzb/__init__.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
================================================
FILE: sickrage/clients/nzb/download_station.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import os
import re
from urllib.parse import urljoin
from requests import RequestException
import sickrage
from sickrage.clients import NZBClient
class DownloadStationAPI(NZBClient):
def __init__(self, host=None, username=None, password=None):
super(DownloadStationAPI, self).__init__('DownloadStation', host, username, password)
self.urls = {
'auth': urljoin(self.host, 'webapi/auth.cgi'),
'task': urljoin(self.host, 'webapi/DownloadStation/task.cgi'),
'info': urljoin(self.host, '/webapi/DownloadStation/info.cgi'),
}
self.url = self.urls['task']
self.checked_destination = False
self.destination = sickrage.app.config.synology.path
self.post_task = {
'method': 'create',
'version': '1',
'api': 'SYNO.DownloadStation.Task',
'session': 'DownloadStation',
}
generic_errors = {
100: 'Unknown error',
101: 'Invalid parameter',
102: 'The requested API does not exist',
103: 'The requested method does not exist',
104: 'The requested version does not support the functionality',
105: 'The logged in session does not have permission',
106: 'Session timeout',
107: 'Session interrupted by duplicate login',
}
self.error_map = {
'create': {
400: 'File upload failed',
401: 'Max number of tasks reached',
402: 'Destination denied',
403: 'Destination does not exist',
404: 'Invalid task id',
405: 'Invalid task action',
406: 'No default destination',
407: 'Set destination failed',
408: 'File does not exist'
},
'login': {
400: 'No such account or incorrect password',
401: 'Account disabled',
402: 'Permission denied',
403: '2-step verification code required',
404: 'Failed to authenticate 2-step verification code'
}
}
for api_method in self.error_map:
self.error_map[api_method].update(generic_errors)
def _check_response(self):
try:
resp = self._response.json()
except (ValueError, AttributeError):
self.session.cookies.clear()
self.auth = False
return self.auth
else:
self.auth = resp.get('success')
if not self.auth:
error_code = resp.get('error', {}).get('code')
api_method = resp.get('method', 'login')
log_string = self.error_map.get(api_method)[error_code]
sickrage.app.log.info('{}: {}'.format(self.name, log_string))
self.session.cookies.clear()
elif resp.get('data', {}).get('sid'):
self.post_task['_sid'] = resp['data']['sid']
return self.auth
def _get_auth(self):
if self.auth:
return self.auth
params = {
'api': 'SYNO.API.Auth',
'version': 2,
'method': 'login',
'account': self.username,
'passwd': self.password,
'session': 'DownloadStation',
'format': 'cookie'
}
try:
# login to API
self.response = self.session.get(self.urls['auth'], params=params, verify=False)
# get sid
self.auth = self.response
except Exception:
self.session.cookies.clear()
self.auth = False
return self.auth
return self._check_response()
def _add_nzb_uri(self, result):
data = self.post_task
data['uri'] = result.url
return self._send_dsm_request(method='post', data=data)
def _add_nzb_file(self, result):
data = self.post_task
files = {'file': ('{}.nzb'.format(result.name), result.content)}
return self._send_dsm_request(method='post', data=data, files=files)
def _check_destination(self):
"""Validate and set nzb destination."""
nzb_path = sickrage.app.config.synology.path
if not (self.auth or self._get_auth()):
return False
if self.checked_destination and self.destination == nzb_path:
return True
params = {
'api': 'SYNO.DownloadStation.Info',
'version': 2,
'method': 'getinfo',
'session': 'DownloadStation',
}
try:
self.response = self.session.get(self.urls['info'], params=params, verify=False, timeout=120)
except RequestException:
self.session.cookies.clear()
self.auth = False
return False
destination = ''
if self._check_response():
jdata = self.response.json()
version_string = jdata.get('data', {}).get('version_string')
if not version_string:
sickrage.app.log.warning('Could not get the version string from DSM: {}'.format(jdata))
return False
# This is DSM6, lets make sure the location is relative
if nzb_path and os.path.isabs(nzb_path):
nzb_path = re.sub(r'^/volume\d/', '', nzb_path).lstrip('/')
else:
# Since they didn't specify the location in the settings,
# lets make sure the default is relative,
# or forcefully set the location setting
params.update({
'method': 'getconfig',
'version': 2,
})
try:
self.response = self.session.get(self.urls['info'], params=params, verify=False, timeout=120)
except RequestException:
self.session.cookies.clear()
self.auth = False
return False
if self._check_response():
jdata = self.response.json()
destination = jdata.get('data', {}).get('default_destination')
if not destination:
sickrage.app.log.info('Default destination could not be determined for DSM6: {}'.format(jdata))
return False
elif os.path.isabs(destination):
nzb_path = re.sub(r'^/volume\d/', '', destination).lstrip('/')
if destination or nzb_path:
sickrage.app.log.info('Destination is now {}'.format(nzb_path or destination))
self.checked_destination = True
self.destination = nzb_path
return True
def _send_dsm_request(self, method, data, **kwargs):
if not self._check_destination():
return False
data['destination'] = self.destination
self._request(method=method, data=data, **kwargs)
return self._check_response()
================================================
FILE: sickrage/clients/nzb/nzbget.py
================================================
# Author: echel0n
# URL: https://sickrage.ca
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
#
# This file is part of SiCKRAGE.
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
from base64 import standard_b64encode
from datetime import date, timedelta
from http import client
from xmlrpc.client import ServerProxy, ProtocolError
import sickrage
from sickrage.core.common import Qualities
from sickrage.core.helpers import try_int
from sickrage.core.tv.show.helpers import find_show
from sickrage.core.websession import WebSession
from sickrage.search_providers import SearchProviderType
class NZBGet(object):
@staticmethod
def sendNZB(nzb, proper=False):
"""
Sends NZB to NZBGet client
:param nzb: nzb object
:param proper: True if this is a Proper download, False if not. Defaults to False
"""
if sickrage.app.config.nzbget.host is None:
sickrage.app.log.warning("No NZBGet host found in configuration. Please configure it.")
return False
dupe_key = ""
dupe_score = 0
addToTop = False
nzbgetprio = 0
category = sickrage.app.config.nzbget.category
show_object = find_show(nzb.series_id, nzb.series_provider_id)
if not show_object:
return False
if show_object.is_anime:
category = sickrage.app.config.nzbget.category_anime
url = "%(protocol)s://%(username)s:%(password)s@%(host)s/xmlrpc" % {
"protocol": 'https' if sickrage.app.config.nzbget.use_https else 'http',
"host": sickrage.app.config.nzbget.host,
"username": sickrage.app.config.nzbget.username,
"password": sickrage.app.config.nzbget.password
}
nzbget_rpc_client = ServerProxy(url)
try:
if nzbget_rpc_client.writelog("INFO", "SiCKRAGE connected to drop of %s any moment now." % (nzb.name + ".nzb")):
sickrage.app.log.debug("Successful connected to NZBGet")
else:
sickrage.app.log.warning("Successful connected to NZBGet, but unable to send a message")
except client.socket.error:
sickrage.app.log.warning("Please check your NZBGet host and port (if it is running). NZBGet is not responding to this combination")
return False
except ProtocolError as e:
if e.errmsg == "Unauthorized":
sickrage.app.log.warning("NZBGet username or password is incorrect.")
else:
sickrage.app.log.warning("NZBGet Protocol Error: " + e.errmsg)
return False
show_object = find_show(nzb.series_id, nzb.series_provider_id)
if not show_object:
return False
# if it aired recently make it high priority and generate DupeKey/Score
for episode_number in nzb.episodes:
episode_object = show_object.get_episode(nzb.season, episode_number)
if dupe_key == "":
dupe_key = f"SiCKRAGE-{episode_object.show.series_provider_id.name}-{episode_object.show.series_id}"
dupe_key += "-" + str(episode_object.season) + "." + str(episode_object.episode)
if date.today() - episode_object.airdate <= timedelta(days=7):
addToTop = True
nzbgetprio = sickrage.app.config.nzbget.priority
else:
category = sickrage.app.config.nzbget.category_backlog
if show_object.is_anime:
category = sickrage.app.config.nzbget.category_anime_backlog
if nzb.quality != Qualities.UNKNOWN:
dupe_score = nzb.quality * 100
if proper:
dupe_score += 10
nzbcontent64 = None
if nzb.provider_type == SearchProviderType.NZBDATA:
data = nzb.extraInfo[0]
nzbcontent64 = standard_b64encode(data)
sickrage.app.log.info("Sending NZB to NZBGet")
sickrage.app.log.debug("URL: " + url)
try:
# Find out if nzbget supports priority (Version 9.0+), old versions beginning with a 0.x will use the old
# command
nzbget_version_str = nzbget_rpc_client.version()
nzbget_version = try_int(nzbget_version_str[:nzbget_version_str.find(".")])
if nzbget_version == 0:
if nzbcontent64 is not None:
nzbget_result = nzbget_rpc_client.append(nzb.name + ".nzb", category, addToTop, nzbcontent64)
else:
if nzb.provider_type == SearchProviderType.NZB:
try:
nzbcontent64 = standard_b64encode(WebSession().get(nzb.url).text)
except Exception:
return False
nzbget_result = nzbget_rpc_client.append(nzb.name + ".nzb", category, addToTop, nzbcontent64)
elif nzbget_version == 12:
if nzbcontent64 is not None:
nzbget_result = nzbget_rpc_client.append(nzb.name + ".nzb", category, nzbgetprio, False,
nzbcontent64, False, dupe_key, dupe_score, "score")
else:
nzbget_result = nzbget_rpc_client.appendurl(nzb.name + ".nzb", category, nzbgetprio, False,
nzb.url, False, dupe_key, dupe_score, "score")
# v13+ has a new combined append method that accepts both (url and content)
# also the return value has changed from boolean to integer
# (Positive number representing NZBID of the queue item. 0 and negative numbers represent error codes.)
elif nzbget_version >= 13:
nzbget_result = True if nzbget_rpc_client.append(nzb.name + ".nzb",
nzbcontent64 if nzbcontent64 is not None else nzb.url,
category, nzbgetprio, False, False, dupe_key, dupe_score,
"score") > 0 else False
else:
if nzbcontent64 is not None:
nzbget_result = nzbget_rpc_client.append(nzb.name + ".nzb", category, nzbgetprio, False,
nzbcontent64)
else:
nzbget_result = nzbget_rpc_client.appendurl(nzb.name + ".nzb", category, nzbgetprio, False,
nzb.url)
if nzbget_result:
sickrage.app.log.debug("NZB sent to NZBGet successfully")
return True
else:
sickrage.app.log.warning("NZBGet could not add %s to the queue" % (nzb.name + ".nzb"))
return False
except Exception:
sickrage.app.log.warning("Connect Error to NZBGet: could not add %s to the queue" % (nzb.name + ".nzb"))
return False
================================================
FILE: sickrage/clients/nzb/sabnzbd.py
================================================
# Author: echel0n
# URL: https://sickrage.ca
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage
#
# This file is part of SiCKRAGE.
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
import datetime
import json
from urllib.parse import urljoin
import sickrage
from sickrage.core.tv.show.helpers import find_show
from sickrage.core.websession import WebSession
from sickrage.core.databases.main import MainDB
from sickrage.search_providers import SearchProviderType
class SabNZBd(object):
@staticmethod
def sendNZB(nzb):
"""
Sends an NZB to SABnzbd via the API.
:param nzb: The NZBSearchResult object to send to SAB
"""
show_object = find_show(nzb.series_id, nzb.series_provider_id)
if not show_object:
return False
category = sickrage.app.config.sabnzbd.category
if show_object.is_anime:
category = sickrage.app.config.sabnzbd.category_anime
# if it aired more than 7 days ago, override with the backlog category IDs
for episode__number in nzb.episodes:
episode_object = show_object.get_episode(nzb.season, episode__number)
if datetime.date.today() - episode_object.airdate > datetime.timedelta(days=7):
category = sickrage.app.config.sabnzbd.category_anime_backlog if episode_object.show.is_anime else sickrage.app.config.sabnzbd.category_backlog
# set up a dict with the URL params in it
params = {'output': 'json'}
if sickrage.app.config.sabnzbd.username:
params['ma_username'] = sickrage.app.config.sabnzbd.username
if sickrage.app.config.sabnzbd.password:
params['ma_password'] = sickrage.app.config.sabnzbd.password
if sickrage.app.config.sabnzbd.apikey:
params['apikey'] = sickrage.app.config.sabnzbd.apikey
if category:
params['cat'] = category
if nzb.priority:
params['priority'] = 2 if sickrage.app.config.sabnzbd.forced else 1
sickrage.app.log.info('Sending NZB to SABnzbd')
url = urljoin(sickrage.app.config.sabnzbd.host, 'api')
try:
jdata = None
if nzb.provider_type == SearchProviderType.NZB:
params['mode'] = 'addurl'
params['name'] = nzb.url
jdata = WebSession().get(url, params=params, verify=False).json()
elif nzb.provider_type == SearchProviderType.NZBDATA:
params['mode'] = 'addfile'
multiPartParams = {'nzbfile': (nzb.name + '.nzb', nzb.extraInfo[0])}
jdata = WebSession().get(url, params=params, file=multiPartParams, verify=False).json()
if not jdata:
raise Exception
except Exception:
sickrage.app.log.info('Error connecting to sab, no data returned')
return False
sickrage.app.log.debug('Result text from SAB: {}'.format(jdata))
result, error_ = SabNZBd._check_sab_response(jdata)
return result
@staticmethod
def _check_sab_response(jdata):
"""
Check response from SAB
:param jdata: Response from requests api call
:return: a list of (Boolean, string) which is True if SAB is not reporting an error
"""
error = jdata.get('error')
if error:
sickrage.app.log.warning("SABnzbd Error: {}".format(error))
return not error, error or json.dumps(jdata)
@staticmethod
def get_sab_access_method(host=None):
"""
Find out how we should connect to SAB
:param host: hostname where SAB lives
:return: (boolean, string) with True if method was successful
"""
params = {
'mode': 'auth',
'output': 'json',
'ma_username': sickrage.app.config.sabnzbd.username,
'ma_password': sickrage.app.config.sabnzbd.username,
'apikey': sickrage.app.config.sabnzbd.apikey
}
url = urljoin(host, 'api')
try:
data = WebSession().get(url, params=params, verify=False).json()
if not data:
return False, data
except Exception:
return False, ""
return SabNZBd._check_sab_response(data)
@staticmethod
def test_authentication(host=None, username=None, password=None, apikey=None):
"""
Sends a simple API request to SAB to determine if the given connection information is connect
:param host: The host where SAB is running (incl port)
:param username: The username to use for the HTTP request
:param password: The password to use for the HTTP request
:param apikey: The API key to provide to SAB
:return: A tuple containing the success boolean and a message
"""
# build up the URL parameters
params = {
'mode': 'queue',
'output': 'json',
'ma_username': username,
'ma_password': password,
'apikey': apikey
}
url = urljoin(host, 'api')
try:
# check the result and determine if it's good or not
data = WebSession().get(url, params=params, verify=False).json()
if not data:
return False, data
result, sab_text = SabNZBd._check_sab_response(data)
if not result:
return False, sab_text
except Exception:
return False, ""
return True, 'Success'
================================================
FILE: sickrage/clients/torrent/__init__.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
================================================
FILE: sickrage/clients/torrent/deluge.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
from base64 import b64encode
import sickrage
from sickrage.clients import TorrentClient
from sickrage.core.tv.show.helpers import find_show
class DelugeAPI(TorrentClient):
def __init__(self, host=None, username=None, password=None):
super(DelugeAPI, self).__init__('Deluge', host, username, password)
self.url = self.host + 'json'
self.session.headers.update({'Content-type': "application/json"})
def _get_auth(self):
post_data = {"method": "auth.login",
"params": [self.password],
"id": 1}
self.response = self.session.post(self.url, json=post_data, verify=bool(sickrage.app.config.torrent.verify_cert))
if not self.response or not self.response.content:
return None
try:
data = self.response.json()
except ValueError:
return None
self.auth = data.get("result")
post_data = {
"method": "web.connected",
"params": [],
"id": 10
}
self.response = self.session.post(self.url, json=post_data, verify=bool(sickrage.app.config.torrent.verify_cert))
if not self.response or not self.response.content:
return None
try:
connected = self.response.json()
except ValueError:
return None
if not connected.get('result'):
post_data = {
"method": "web.get_hosts",
"params": [],
"id": 11
}
self.response = self.session.post(self.url, json=post_data, verify=bool(sickrage.app.config.torrent.verify_cert))
if not self.response or not self.response.content:
return None
try:
hosts = self.response.json()
except ValueError:
return None
if not hosts.get('result'):
sickrage.app.log.warning(self.name + ': WebUI does not contain daemons')
return None
post_data = {
"method": "web.connect",
"params": [hosts[0][0]],
"id": 11
}
self.response = self.session.post(self.url, json=post_data, verify=bool(sickrage.app.config.torrent.verify_cert))
if not self.response:
return None
post_data = {
"method": "web.connected",
"params": [],
"id": 10
}
self.response = self.session.post(self.url, json=post_data, verify=bool(sickrage.app.config.torrent.verify_cert))
if not self.response or not self.response.content:
return None
try:
connected = self.response.json()
except ValueError:
return None
if not connected.get('result'):
sickrage.app.log.warning(self.name + ': WebUI could not connect to daemon')
return None
return self.auth
def _add_torrent_uri(self, result):
post_data = {"method": "core.add_torrent_magnet",
"params": [result.url, {}],
"id": 2}
self._request(method='post', json=post_data)
result.hash = self.response.json()['result']
return self.response.json()['result']
def _add_torrent_file(self, result):
post_data = {"method": "core.add_torrent_file",
"params": [result.name + '.torrent', b64encode(result.content), {}],
"id": 2}
self._request(method='post', json=post_data)
result.hash = self.response.json()['result']
return self.response.json()['result']
def _set_torrent_label(self, result):
label = sickrage.app.config.torrent.label
tv_show = find_show(result.series_id, result.series_provider_id)
if tv_show.is_anime:
label = sickrage.app.config.torrent.label_anime
if ' ' in label:
sickrage.app.log.warning(self.name + ': Invalid label. Label must not contain a space')
return False
if label:
# check if label already exists and create it if not
post_data = {"method": 'label.get_labels',
"params": [],
"id": 3}
self._request(method='post', json=post_data)
labels = self.response.json()['result']
if labels is not None:
if label not in labels:
sickrage.app.log.debug(self.name + ': ' + label + " label does not exist in Deluge we must add it")
post_data = {"method": 'label.add',
"params": [label],
"id": 4}
self._request(method='post', json=post_data)
sickrage.app.log.debug(self.name + ': ' + label + " label added to Deluge")
# add label to torrent
post_data = {"method": 'label.set_torrent',
"params": [result.hash, label],
"id": 5}
self._request(method='post', json=post_data)
sickrage.app.log.debug(self.name + ': ' + label + " label added to torrent")
else:
sickrage.app.log.debug(self.name + ': ' + "label plugin not detected")
return False
return not self.response.json()['error']
def _set_torrent_ratio(self, result):
ratio = None
if result.ratio:
ratio = result.ratio
if ratio:
post_data = {"method": "core.set_torrent_stop_at_ratio",
"params": [result.hash, True],
"id": 5}
self._request(method='post', json=post_data)
post_data = {"method": "core.set_torrent_stop_ratio",
"params": [result.hash, float(ratio)],
"id": 6}
self._request(method='post', json=post_data)
return not self.response.json()['error']
return True
def _set_torrent_path(self, result):
if sickrage.app.config.torrent.path:
post_data = {"method": "core.set_torrent_move_completed",
"params": [result.hash, True],
"id": 7}
self._request(method='post', json=post_data)
post_data = {"method": "core.set_torrent_move_completed_path",
"params": [result.hash, sickrage.app.config.torrent.path],
"id": 8}
self._request(method='post', json=post_data)
return not self.response.json()['error']
return True
def _set_torrent_pause(self, result):
if sickrage.app.config.torrent.paused:
post_data = {"method": "core.pause_torrent",
"params": [[result.hash]],
"id": 9}
self._request(method='post', json=post_data)
return not self.response.json()['error']
return True
================================================
FILE: sickrage/clients/torrent/deluged.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
from base64 import b64encode
from deluge_client import DelugeRPCClient
import sickrage
from sickrage.clients import TorrentClient
from sickrage.core.tv.show.helpers import find_show
class DelugeDAPI(TorrentClient):
drpc = None
def __init__(self, host=None, username=None, password=None):
super(DelugeDAPI, self).__init__('DelugeD', host, username, password)
def _get_auth(self):
if not self.connect():
return None
return True
def connect(self, reconnect=False):
hostname = self.host.replace("/", "").split(':')
if not len(hostname) == 3:
return self.drpc
if not self.drpc or reconnect:
self.drpc = DelugeRPC(hostname[1], port=hostname[2], username=self.username, password=self.password)
return self.drpc
def _add_torrent_uri(self, result):
# label = sickrage.TORRENT_LABEL
# if result.show.is_anime:
# label = sickrage.TORRENT_LABEL_ANIME
options = {
'add_paused': sickrage.app.config.torrent.paused
}
remote_torrent = self.drpc.add_torrent_magnet(result.url, options, result.hash)
if not remote_torrent:
return None
result.hash = remote_torrent
return remote_torrent
def _add_torrent_file(self, result):
# label = sickrage.TORRENT_LABEL
# if result.show.is_anime:
# label = sickrage.TORRENT_LABEL_ANIME
if not result.content:
result.content = {}
return None
options = {
'add_paused': sickrage.app.config.torrent.paused
}
remote_torrent = self.drpc.add_torrent_file(result.name + '.torrent', result.content, options, result.hash)
if not remote_torrent:
return None
result.hash = remote_torrent
return remote_torrent
def _set_torrent_label(self, result):
label = sickrage.app.config.torrent.label
tv_show = find_show(result.series_id, result.series_provider_id)
if tv_show.is_anime:
label = sickrage.app.config.torrent.label_anime
if ' ' in label:
sickrage.app.log.warning(self.name + ': Invalid label. Label must not contain a space')
return False
if label:
return self.drpc.set_torrent_label(result.hash, label)
return True
def _set_torrent_ratio(self, result):
if result.ratio:
ratio = float(result.ratio)
return self.drpc.set_torrent_ratio(result.hash, ratio)
return True
def _set_torrent_priority(self, result):
if result.priority == 1:
return self.drpc.set_torrent_priority(result.hash, True)
return True
def _set_torrent_path(self, result):
path = sickrage.app.config.torrent.path
if path:
return self.drpc.set_torrent_path(result.hash, path)
return True
def _set_torrent_pause(self, result):
if sickrage.app.config.torrent.paused:
return self.drpc.pause_torrent(result.hash)
return True
def test_authentication(self):
if self.connect(True) and self.drpc.test():
return True, 'Success: Connected and Authenticated'
else:
return False, 'Error: Unable to Authenticate! Please check your config!'
class DelugeRPC(object):
host = 'localhost'
port = 58846
username = None
password = None
client = None
def __init__(self, host='localhost', port=58846, username=None, password=None):
super(DelugeRPC, self).__init__()
self.host = host
self.port = port
self.username = username
self.password = password
def connect(self):
self.client = DelugeRPCClient(self.host, int(self.port), self.username, self.password)
self.client.connect()
return self.client.connected
def disconnect(self):
self.client.disconnect()
def test(self):
try:
return self.connect()
except Exception:
return False
def add_torrent_magnet(self, torrent, options, torrent_hash):
try:
if not self.connect():
return False
torrent_id = self.client.core.add_torrent_magnet(torrent, options).get()
if not torrent_id:
torrent_id = self._check_torrent(torrent_hash)
except Exception:
return False
finally:
if self.client:
self.disconnect()
return torrent_id
def add_torrent_file(self, filename, torrent, options, torrent_hash):
try:
if not self.connect():
return False
torrent_id = self.client.core.add_torrent_file(filename, b64encode(torrent), options).get()
if not torrent_id:
torrent_id = self._check_torrent(torrent_hash)
except Exception:
return False
finally:
if self.client:
self.disconnect()
return torrent_id
def set_torrent_label(self, torrent_id, label):
try:
if not self.connect():
return False
self.client.label.set_torrent(torrent_id, label).get()
except Exception:
return False
finally:
if self.client:
self.disconnect()
return True
def set_torrent_path(self, torrent_id, path):
try:
if not self.connect():
return False
self.client.core.set_torrent_move_completed_path(torrent_id, path).get()
self.client.core.set_torrent_move_completed(torrent_id, 1).get()
except Exception:
return False
finally:
if self.client:
self.disconnect()
return True
def set_torrent_priority(self, torrent_ids, priority):
try:
if not self.connect():
return False
if priority:
self.client.core.queue_top([torrent_ids]).get()
except Exception as err:
return False
finally:
if self.client:
self.disconnect()
return True
def set_torrent_ratio(self, torrent_ids, ratio):
try:
if not self.connect():
return False
self.client.core.set_torrent_stop_at_ratio(torrent_ids, True).get()
self.client.core.set_torrent_stop_ratio(torrent_ids, ratio).get()
except Exception as err:
return False
finally:
if self.client:
self.disconnect()
return True
def pause_torrent(self, torrent_ids):
try:
if not self.connect():
return False
self.client.core.pause_torrent(torrent_ids).get()
except Exception:
return False
finally:
if self.client:
self.disconnect()
return True
def _check_torrent(self, torrent_hash):
torrent_id = self.client.core.get_torrent_status(torrent_hash, {}).get()
if torrent_id['hash']:
sickrage.app.log.debug('DelugeD: Torrent already exists in Deluge')
return torrent_hash
return False
================================================
FILE: sickrage/clients/torrent/download_station.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import os
import re
from urllib.parse import urljoin
import sickrage
from sickrage.clients import TorrentClient
class DownloadStationAPI(TorrentClient):
def __init__(self, host=None, username=None, password=None):
super(DownloadStationAPI, self).__init__('DownloadStation', host, username, password)
self.urls = {
'auth': urljoin(self.host, '/webapi/auth.cgi'),
'query': urljoin(self.host, '/webapi/query.cgi'),
'task': urljoin(self.host, '/webapi/DownloadStation/task.cgi'),
'info': urljoin(self.host, '/webapi/DownloadStation/info.cgi'),
}
self.url = self.urls['task']
self.checked_destination = False
self.destination = sickrage.app.config.torrent.path
self.post_task = {
'method': 'create',
'api': 'SYNO.DownloadStation.Task',
'session': 'DownloadStation',
}
generic_errors = {
100: 'Unknown error',
101: 'Invalid parameter',
102: 'The requested API does not exist',
103: 'The requested method does not exist',
104: 'The requested version does not support the functionality',
105: 'The logged in session does not have permission',
106: 'Session timeout',
107: 'Session interrupted by duplicate login',
}
self.error_map = {
'create': {
400: 'File upload failed',
401: 'Max number of tasks reached',
402: 'Destination denied',
403: 'Destination does not exist',
404: 'Invalid task id',
405: 'Invalid task action',
406: 'No default destination',
407: 'Set destination failed',
408: 'File does not exist'
},
'login': {
400: 'No such account or incorrect password',
401: 'Account disabled',
402: 'Permission denied',
403: '2-step verification code required',
404: 'Failed to authenticate 2-step verification code'
}
}
for api_method in self.error_map:
self.error_map[api_method].update(generic_errors)
def _check_response(self):
try:
resp = self._response.json()
except (ValueError, AttributeError):
self.session.cookies.clear()
self.auth = False
return self.auth
else:
self.auth = resp.get('success')
if not self.auth:
error_code = resp.get('error', {}).get('code')
api_method = resp.get('method', 'login')
log_string = self.error_map.get(api_method)[error_code]
sickrage.app.log.info('{}: {}'.format(self.name, log_string))
self.session.cookies.clear()
elif resp.get('data', {}).get('sid'):
self.post_task['_sid'] = resp['data']['sid']
return self.auth
def _get_auth(self):
if self.auth:
return self.auth
params = {
'api': 'SYNO.API.Auth',
'method': 'login',
'account': self.username,
'passwd': self.password,
'session': 'DownloadStation',
'format': 'cookie'
}
api_info = self._get_api_info(params['api'])
params['version'] = api_info.get('maxVersion')
self.response = self.session.get(self.urls['auth'], params=params, verify=bool(sickrage.app.config.torrent.verify_cert))
if not self.response:
self.session.cookies.clear()
self.auth = False
return self.auth
# get sid
self.auth = self.response
return self._check_response()
def _get_api_info(self, method):
json_data = {}
params = {
'api': 'SYNO.API.Info',
'version': 1,
'method': 'query',
'query': method
}
resp = self.session.get(self.urls['query'], params=params, verify=bool(sickrage.app.config.torrent.verify_cert))
if not resp:
return json_data
try:
json_resp = resp.json()
except (ValueError, AttributeError):
return json_data
else:
success = json_resp.get('success')
if success:
json_data = json_resp.get('data')
return json_data.get(method, {})
def _add_torrent_uri(self, result):
data = self.post_task
api_info = self._get_api_info(data['api'])
data['version'] = api_info.get('maxVersion')
data['uri'] = result.url
return self._send_dsm_request(method='post', data=data)
def _add_torrent_file(self, result):
data = self.post_task
api_info = self._get_api_info(data['api'])
data['version'] = api_info.get('maxVersion')
files = {'file': ('{}.torrent'.format(result.name), result.content)}
return self._send_dsm_request(method='post', data=data, files=files)
def _check_destination(self):
"""Validate and set torrent destination."""
torrent_path = sickrage.app.config.torrent.path
if not (self.auth or self._get_auth()):
return False
if self.checked_destination and self.destination == torrent_path:
return True
params = {
'api': 'SYNO.DownloadStation.Info',
'method': 'getinfo',
'session': 'DownloadStation',
}
api_info = self._get_api_info(params['api'])
params['version'] = api_info.get('maxVersion')
self.response = self.session.get(self.urls['info'], params=params, verify=False, timeout=120)
if not self.response or not self.response.content:
self.session.cookies.clear()
self.auth = False
return False
destination = ''
if self._check_response():
jdata = self.response.json()
version_string = jdata.get('data', {}).get('version_string')
if not version_string:
sickrage.app.log.warning('Could not get the version string from DSM: {}'.format(jdata))
return False
# This is DSM6, lets make sure the location is relative
if torrent_path and os.path.isabs(torrent_path):
torrent_path = re.sub(r'^/volume\d/', '', torrent_path).lstrip('/')
else:
# Since they didn't specify the location in the settings,
# lets make sure the default is relative,
# or forcefully set the location setting
params.update({
'method': 'getconfig'
})
self.response = self.session.get(self.urls['info'], params=params, verify=False, timeout=120)
if not self.response or not self.response.content:
self.session.cookies.clear()
self.auth = False
return False
if self._check_response():
jdata = self.response.json()
destination = jdata.get('data', {}).get('default_destination')
if not destination:
sickrage.app.log.info('Default destination could not be determined for DSM6: {}'.format(jdata))
return False
elif os.path.isabs(destination):
torrent_path = re.sub(r'^/volume\d/', '', destination).lstrip('/')
if destination or torrent_path:
sickrage.app.log.info('Destination is now {}'.format(torrent_path or destination))
self.checked_destination = True
self.destination = torrent_path
return True
def _send_dsm_request(self, method, data, **kwargs):
if not self._check_destination():
return False
data['destination'] = self.destination
self._request(method=method, data=data, **kwargs)
return self._check_response()
================================================
FILE: sickrage/clients/torrent/mlnet.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import sickrage
from sickrage.clients import TorrentClient
class mlnetAPI(TorrentClient):
def __init__(self, host=None, username=None, password=None):
super(mlnetAPI, self).__init__('mlnet', host, username, password)
self.url = self.host
def _get_auth(self):
self.auth = None
self.response = self.session.get(self.host, auth=(self.username, self.password), verify=bool(sickrage.app.config.torrent.verify_cert))
if self.response and self.response.text:
self.auth = self.response.text
return self.auth
def _add_torrent_uri(self, result):
self.url = self.host + 'submit'
params = {'q': 'dllink ' + result.url}
return self._request(method='get', params=params)
def _add_torrent_file(self, result):
self.url = self.host + 'submit'
params = {'q': 'dllink ' + result.url}
return self._request(method='get', params=params)
================================================
FILE: sickrage/clients/torrent/putio.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import re
from urllib.parse import urlencode
import sickrage
from sickrage.clients import TorrentClient
class PutioAPI(TorrentClient):
def __init__(self, host=None, username=None, password=None):
super(PutioAPI, self).__init__('putio', host, username, password)
self.client_id = "48901323822-1arri7nf5i65fartv81e4odekbt8c7td.apps.googleusercontent.com"
self.redirect_uri = 'https://auth.sickrage.ca/auth'
self.url = 'https://api.put.io/login'
def _get_auth(self):
next_params = {
'client_id': self.client_id,
'response_type': 'token',
'redirect_uri': self.redirect_uri
}
post_data = {
'name': self.username,
'password': self.password,
'next': '/v2/oauth2/authenticate?' + urlencode(next_params)
}
self.auth = None
response = self.session.post(self.url, data=post_data, verify=bool(sickrage.app.config.torrent.verify_cert))
if not response:
return None
response = self.session.get(response.headers['location'], verify=bool(sickrage.app.config.torrent.verify_cert))
if not response:
return None
resulting_uri = '{redirect_uri}#access_token=(.*)'.format(redirect_uri=re.escape(self.redirect_uri))
auth_match = re.search(resulting_uri, response.headers.get('location'))
if auth_match:
self.auth = auth_match.group(1)
return self.auth
def _add_torrent_uri(self, result):
post_data = {
'url': result.url,
'save_parent_id': 0,
'extract': True,
'oauth_token': self.auth
}
self.response = self.session.post('https://api.put.io/v2/transfers/add', data=post_data)
if not self.response or not self.response.content:
return False
try:
data = self.response.json()
except ValueError:
return False
return data.get("transfer", {}).get('save_parent_id', None) == 0
def _add_torrent_file(self, result):
post_data = {
'name': 'putio_torrent',
'parent': 0,
'oauth_token': self.auth
}
self.session.post('https://api.put.io/v2/files/upload', data=post_data, files=('putio_torrent', result.content))
if not self.response or not self.response.content:
return False
try:
data = self.response.json()
except ValueError:
return False
return data.get('status') == "OK"
================================================
FILE: sickrage/clients/torrent/qbittorrent.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
from urllib.parse import urljoin
from requests import HTTPError
import sickrage
from sickrage.clients import TorrentClient
from sickrage.core.tv.show.helpers import find_show
class QBittorrentAPI(TorrentClient):
def __init__(self, host=None, username=None, password=None):
super(QBittorrentAPI, self).__init__('qbittorrent', host, username, password)
self.api_version = None
def get_api_version(self):
"""Get API version."""
version = (1, 0, 0)
url = urljoin(self.host, 'api/v2/app/webapiVersion')
response = self.session.get(url, verify=sickrage.app.config.torrent.verify_cert)
try:
if response and response.text:
version = tuple(map(int, response.text.split('.')))
version + (0,) * (3 - len(version))
elif response is not None:
status_code = response.status_code
if status_code == 404:
url = urljoin(self.host, 'version/api')
response = self.session.get(url, verify=sickrage.app.config.torrent.verify_cert)
if response and response.text:
version = int(response.text)
version = (1, version % 100, 0)
except ValueError:
pass
return version
def _get_auth(self):
self.auth = False
data = {
'username': self.username,
'password': self.password
}
url = urljoin(self.host, 'api/v2/auth/login')
self.response = self.session.post(url, data=data, verify=sickrage.app.config.torrent.verify_cert)
if self.response and self.response.text and not self.response.text == 'Fails.':
self.session.cookies = self.response.cookies
self.auth = True
elif self.response is not None:
status_code = self.response.status_code
if status_code == 404:
url = urljoin(self.host, 'login')
self.response = self.session.post(url, data=data, verify=sickrage.app.config.torrent.verify_cert)
if self.response:
self.session.cookies = self.response.cookies
self.auth = True
if self.auth:
self.api_version = self.get_api_version()
else:
sickrage.app.log.warning('{name}: Invalid Username or Password, check your config'.format(name=self.name))
return self.auth
def _set_torrent_label(self, result):
label = sickrage.app.config.torrent.label_anime if find_show(result.series_id, result.series_provider_id).is_anime else sickrage.app.config.torrent.label
if not label:
return True
data = {'hashes': result.hash.lower()}
if self.api_version >= (2, 0, 0):
label_key = 'category'
data[label_key.lower()] = label.replace(' ', '_')
self.url = urljoin(self.host, 'api/v2/torrents/setCategory')
elif self.api_version > (1, 6, 0) and label:
label_key = 'Category' if self.api_version >= (1, 10, 0) else 'Label'
data[label_key.lower()] = label.replace(' ', '_')
self.url = urljoin(self.host, 'command/set{}'.format(label_key))
return self._request(method='post', data=data, cookies=self.session.cookies)
def _add_torrent_uri(self, result):
command = 'api/v2/torrents/add' if self.api_version >= (2, 0, 0) else 'command/download'
self.url = urljoin(self.host, command)
data = {'urls': result.url}
return self._request(method='post', data=data, cookies=self.session.cookies)
def _add_torrent_file(self, result):
command = 'api/v2/torrents/add' if self.api_version >= (2, 0, 0) else 'command/upload'
self.url = urljoin(self.host, command)
files = {'torrent': result.content}
return self._request(method='post', files=files, cookies=self.session.cookies)
def _set_torrent_priority(self, result):
command = 'api/v2/torrents' if self.api_version >= (2, 0, 0) else 'command'
priority = '{}Prio'.format('increase' if result.priority == 1 else 'decrease')
self.url = urljoin(self.host, '{command}/{priority}'.format(command=command, priority=priority))
data = {'hashes': result.hash}
return self._request(method='post', data=data, cookies=self.session.cookies)
def _set_torrent_pause(self, result):
command = 'api/v2/torrents' if self.api_version >= (2, 0, 0) else 'command'
state = 'pause' if sickrage.app.config.torrent.paused else 'resume'
self.url = urljoin(self.host, '{command}/{state}'.format(command=command, state=state))
data = {'hashes' if self.api_version >= (1, 18, 0) else 'hash': result.hash}
return self._request(method='post', data=data, cookies=self.session.cookies)
def remove_torrent(self, info_hash):
self.url = urljoin(self.host, 'api/v2/torrents/delete' if self.api_version >= (2, 0, 0) else 'command/deletePerm')
data = {'hashes': info_hash.lower()}
if self.api_version >= (2, 0, 0):
data['deleteFiles'] = True
return self._request(method='post', data=data, cookies=self.session.cookies)
================================================
FILE: sickrage/clients/torrent/rtorrent.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import traceback
from rtorrentlib import RTorrent
import sickrage
from sickrage.clients import TorrentClient
from sickrage.core.tv.show.helpers import find_show
class rTorrentAPI(TorrentClient):
def __init__(self, host=None, username=None, password=None):
super(rTorrentAPI, self).__init__('rTorrent', host, username, password)
def _get_auth(self):
self.auth = None
if self.auth is not None:
return self.auth
if not self.host:
return
tp_kwargs = {}
if sickrage.app.config.torrent.auth_type.lower() != 'none':
tp_kwargs['authtype'] = sickrage.app.config.torrent.auth_type
if not sickrage.app.config.torrent.verify_cert:
tp_kwargs['check_ssl_cert'] = False
if self.username and self.password:
self.auth = RTorrent(self.host, self.username, self.password, True, tp_kwargs=tp_kwargs)
else:
self.auth = RTorrent(self.host, None, None, True)
return self.auth
def _add_torrent_uri(self, result):
if not self.auth:
return False
if not result:
return False
try:
# Send magnet to rTorrent
torrent = self.auth.load_magnet(result.url, result.hash)
if not torrent:
return False
# Set label
label = sickrage.app.config.torrent.label
show_object = find_show(result.series_id, result.series_provider_id)
if show_object.is_anime:
label = sickrage.app.config.torrent.label_anime
if label:
torrent.set_custom(1, label)
if sickrage.app.config.torrent.path:
torrent.set_directory(sickrage.app.config.torrent.path)
# Start torrent
torrent.start()
return True
except Exception:
sickrage.app.log.debug(traceback.format_exc())
return False
def _add_torrent_file(self, result):
if not self.auth:
return False
if not result:
return False
# Send request to rTorrent
try:
# Send torrent to rTorrent
torrent = self.auth.load_torrent(result.content)
if not torrent:
return False
# Set label
label = sickrage.app.config.torrent.label
show_object = find_show(result.series_id, result.series_provider_id)
if show_object.is_anime:
label = sickrage.app.config.torrent.label_anime
if label:
torrent.set_custom(1, label)
if sickrage.app.config.torrent.path:
torrent.set_directory(sickrage.app.config.torrent.path)
# Set Ratio Group
# torrent.set_visible(group_name)
# Start torrent
torrent.start()
return True
except Exception:
sickrage.app.log.debug(traceback.format_exc())
return False
def _set_torrent_ratio(self, name):
# if not name:
# return False
#
# if not self.auth:
# return False
#
# views = self.auth.get_views()
#
# if name not in views:
# self.auth.create_group(name)
# group = self.auth.get_group(name)
# ratio = int(float(sickrage.TORRENT_RATIO) * 100)
#
# try:
# if ratio > 0:
#
# # Explicitly set all group options to ensure it is setup correctly
# group.set_upload('1M')
# group.set_min(ratio)
# group.set_max(ratio)
# group.set_command('d.stop')
# group.enable()
# else:
# # Reset group action and disable it
# group.set_command()
# group.disable()
#
# except:
# return False
return True
def test_authentication(self):
try:
if self._get_auth():
return True, 'Success: Connected and Authenticated'
else:
return False, 'Error: Unable to get ' + self.name + ' Authentication, check your config!'
except Exception:
sickrage.app.log.debug(traceback.format_exc())
return False, 'Error: Unable to connect to ' + self.name
================================================
FILE: sickrage/clients/torrent/transmission.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import os
import re
from base64 import b64encode
import requests
import sickrage
from sickrage.clients import TorrentClient
class TransmissionAPI(TorrentClient):
def __init__(self, host=None, username=None, password=None):
super(TransmissionAPI, self).__init__('Transmission', host, username, password)
if not self.host.endswith('/'):
self.host += '/'
if self.rpcurl.startswith('/'):
self.rpcurl = self.rpcurl[1:]
if self.rpcurl.endswith('/'):
self.rpcurl = self.rpcurl[:-1]
self.url = self.host + self.rpcurl + '/rpc'
def _get_auth(self):
self.response = self.session.post(self.url,
timeout=120,
json={'method': 'session-get'},
auth=(self.username, self.password),
verify=bool(sickrage.app.config.torrent.verify_cert))
if self.response is not None and self.response.text:
auth_match = re.search(r'X-Transmission-Session-Id:\s*(\w+)', self.response.text)
if auth_match:
self.auth = auth_match.group(1)
self.session.headers.update({'x-transmission-session-id': self.auth})
# Validating Transmission authorization
success = self._request(method='post',
json={'arguments': {}, 'method': 'session-get'},
headers={'x-transmission-session-id': self.auth})
if not success:
self.auth = None
else:
self.auth = None
return self.auth
def _add_torrent_uri(self, result):
arguments = {
'filename': result.url,
'paused': 1 if sickrage.app.config.torrent.paused else 0,
}
if os.path.isabs(sickrage.app.config.torrent.path):
arguments['download-dir'] = sickrage.app.config.torrent.path
post_data = {
'arguments': arguments,
'method': 'torrent-add'
}
if self._request(method='post', json=post_data):
return self.response.json()['result'] == "success"
def _add_torrent_file(self, result):
arguments = {
'metainfo': b64encode(result.content),
'paused': 1 if sickrage.app.config.torrent.paused else 0
}
if os.path.isabs(sickrage.app.config.torrent.path):
arguments['download-dir'] = sickrage.app.config.torrent.path
post_data = {
'arguments': arguments,
'method': 'torrent-add'
}
if self._request(method='post', json=post_data):
return self.response.json()['result'] == "success"
def _set_torrent_ratio(self, result):
ratio = None
if isinstance(result.ratio, int):
ratio = result.ratio
mode = 0
if ratio:
if float(ratio) == -1:
ratio = 0
mode = 2
elif float(ratio) >= 0:
ratio = float(ratio)
mode = 1 # Stop seeding at seedRatioLimit
arguments = {
'ids': [result.hash],
'seedRatioLimit': ratio,
'seedRatioMode': mode
}
post_data = {
'arguments': arguments,
'method': 'torrent-set'
}
if self._request(method='post', json=post_data):
return self.response.json()['result'] == "success"
def _set_torrent_seed_time(self, result):
if sickrage.app.config.torrent.seed_time and sickrage.app.config.torrent.seed_time != -1:
time = int(60 * float(sickrage.app.config.torrent.seed_time))
arguments = {
'ids': [result.hash],
'seedIdleLimit': time,
'seedIdleMode': 1
}
post_data = {
'arguments': arguments,
'method': 'torrent-set'
}
if self._request(method='post', json=post_data):
return self.response.json()['result'] == "success"
else:
return True
def _set_torrent_priority(self, result):
arguments = {'ids': [result.hash]}
if result.priority == -1:
arguments['priority-low'] = []
elif result.priority == 1:
# set high priority for all files in torrent
arguments['priority-high'] = []
# move torrent to the top if the queue
arguments['queuePosition'] = 0
if sickrage.app.config.torrent.high_bandwidth:
arguments['bandwidthPriority'] = 1
else:
arguments['priority-normal'] = []
post_data = {
'arguments': arguments,
'method': 'torrent-set'
}
if self._request(method='post', json=post_data):
return self.response.json()['result'] == "success"
def remove_torrent(self, info_hash):
arguments = {
'ids': [info_hash],
'delete-local-data': 1,
}
post_data = {
'arguments': arguments,
'method': 'torrent-remove',
}
if self._request(method='post', json=post_data):
return self.response.json()['result'] == "success"
================================================
FILE: sickrage/clients/torrent/utorrent.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import re
import sickrage
from sickrage.clients import TorrentClient
from sickrage.core.tv.show.helpers import find_show
class uTorrentAPI(TorrentClient):
def __init__(self, host=None, username=None, password=None):
super(uTorrentAPI, self).__init__('uTorrent', host, username, password)
self.url = self.host + 'gui/'
def _request(self, method='get', data=None, params=None, *args, **kwargs):
# Workaround for uTorrent 2.2.1
# Need a odict but only supported in 2.7+ and sickrage is 2.6+
ordered_params = {'token': self.auth}
for k, v in params.items() or {}:
ordered_params.update({k: v})
return super(uTorrentAPI, self)._request(method=method, params=ordered_params, data=data, *args, **kwargs)
def _get_auth(self):
self.auth = None
self.response = self.session.get(self.url + 'token.html',
timeout=120, auth=(self.username, self.password),
verify=bool(sickrage.app.config.torrent.verify_cert))
if self.response and self.response.text:
auth_match = re.findall("(.*?)", self.response.text)
if auth_match:
self.auth = auth_match[0]
self.cookies = self.response.cookies
return self.auth
def _add_torrent_uri(self, result):
params = {'action': 'add-url', 's': result.url[:1024]}
return self._request(params=params, cookies=self.cookies)
def _add_torrent_file(self, result):
params = {'action': 'add-file'}
files = {'torrent_file': (result.name + '.torrent', result.content)}
return self._request(method='post', params=params, files=files, cookies=self.cookies)
def _set_torrent_label(self, result):
label = sickrage.app.config.torrent.label
show_object = find_show(result.series_id, result.series_provider_id)
if show_object.is_anime:
label = sickrage.app.config.torrent.label_anime
params = {'action': 'setprops',
'hash': result.hash,
's': 'label',
'v': label}
return self._request(params=params, cookies=self.cookies)
def _set_torrent_ratio(self, result):
ratio = None
if result.ratio:
ratio = result.ratio
if ratio:
params = {'action': 'setprops',
'hash': result.hash,
's': 'seed_override',
'v': '1'}
if self._request(params=params, cookies=self.cookies):
params = {'action': 'setprops',
'hash': result.hash,
's': 'seed_ratio',
'v': float(ratio) * 10}
return self._request(params=params, cookies=self.cookies)
else:
return False
return True
def _set_torrent_seed_time(self, result):
if sickrage.app.config.torrent.seed_time:
time = 3600 * float(sickrage.app.config.torrent.seed_time)
params = {'action': 'setprops',
'hash': result.hash,
's': 'seed_override',
'v': '1'}
if self._request(params=params, cookies=self.cookies):
params = {'action': 'setprops',
'hash': result.hash,
's': 'seed_time',
'v': time}
return self._request(params=params, cookies=self.cookies)
else:
return False
else:
return True
def _set_torrent_priority(self, result):
if result.priority == 1:
params = {'action': 'queuetop', 'hash': result.hash}
return self._request(params=params, cookies=self.cookies)
else:
return True
def _set_torrent_pause(self, result):
if sickrage.app.config.torrent.paused:
params = {'action': 'pause', 'hash': result.hash}
else:
params = {'action': 'start', 'hash': result.hash}
return self._request(params=params, cookies=self.cookies)
================================================
FILE: sickrage/core/__init__.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import asyncio
import datetime
import locale
import logging
import os
import platform
import re
import shutil
import socket
import sys
import threading
import traceback
import uuid
from collections import deque
from urllib.parse import uses_netloc
from urllib.request import FancyURLopener
import rarfile
import sentry_sdk
from apscheduler.schedulers import SchedulerNotRunningError
from apscheduler.schedulers.tornado import TornadoScheduler
from apscheduler.triggers.interval import IntervalTrigger
from dateutil import tz
from fake_useragent import UserAgent
from sentry_sdk.integrations.logging import LoggingIntegration, ignore_logger
from tornado.ioloop import IOLoop, PeriodicCallback
from tornado.platform.asyncio import AnyThreadEventLoopPolicy
import sickrage
from sickrage.core.amqp.consumer import AMQPConsumer
from sickrage.core.announcements import Announcements
from sickrage.core.api import API
from sickrage.core.auth import AuthServer
from sickrage.core.auto_backup import AutoBackup
from sickrage.core.common import Quality, Qualities, EpisodeStatus
from sickrage.core.config import Config
from sickrage.core.config.helpers import change_gui_lang
from sickrage.core.databases.cache import CacheDB
from sickrage.core.databases.config import ConfigDB, CustomStringEncryptedType
from sickrage.core.databases.main import MainDB
from sickrage.core.enums import MultiEpNaming, DefaultHomePage, NzbMethod, TorrentMethod, CheckPropersInterval
from sickrage.core.helpers import generate_secret, make_dir, restore_app_data, get_disk_space_usage, get_free_space, launch_browser, torrent_webui_url, \
encryption, md5_file_hash, flatten, get_internal_ip
from sickrage.core.logger import Logger
from sickrage.core.nameparser.validator import check_force_season_folders
from sickrage.core.processors import auto_postprocessor
from sickrage.core.processors.auto_postprocessor import AutoPostProcessor
from sickrage.core.queues.postprocessor import PostProcessorQueue
from sickrage.core.queues.search import SearchQueue
from sickrage.core.queues.show import ShowQueue
from sickrage.core.searchers.backlog_searcher import BacklogSearcher
from sickrage.core.searchers.daily_searcher import DailySearcher
from sickrage.core.searchers.failed_snatch_searcher import FailedSnatchSearcher
from sickrage.core.searchers.proper_searcher import ProperSearcher
from sickrage.core.searchers.subtitle_searcher import SubtitleSearcher
from sickrage.core.searchers.trakt_searcher import TraktSearcher
from sickrage.core.tv.show import TVShow
from sickrage.core.tv.show.helpers import get_show_list
from sickrage.core.ui import Notifications
from sickrage.core.updaters.rsscache_updater import RSSCacheUpdater
from sickrage.core.updaters.show_updater import ShowUpdater
from sickrage.core.updaters.tz_updater import TimeZoneUpdater
from sickrage.core.upnp import UPNPClient
from sickrage.core.version_updater import VersionUpdater, SourceUpdateManager
from sickrage.core.webserver import WebServer
from sickrage.core.websocket import check_web_socket_queue
from sickrage.metadata_providers import MetadataProviders
from sickrage.notification_providers import NotificationProviders
from sickrage.search_providers import SearchProviders
from sickrage.series_providers import SeriesProviders
class Core(object):
def __init__(self):
self.started = False
self.loading_shows = False
self.daemon = None
self.pid = os.getpid()
self.gui_static_dir = os.path.join(sickrage.PROG_DIR, 'core', 'webserver', 'static')
self.gui_views_dir = os.path.join(sickrage.PROG_DIR, 'core', 'webserver', 'views')
self.gui_app_dir = os.path.join(sickrage.PROG_DIR, 'core', 'webserver', 'app')
self.trakt_api_key = '5c65f55e11d48c35385d9e8670615763a605fad28374c8ae553a7b7a50651ddd'
self.trakt_api_secret = 'b53e32045ac122a445ef163e6d859403301ffe9b17fb8321d428531b69022a82'
self.trakt_app_id = '4562'
self.fanart_api_key = '9b3afaf26f6241bdb57d6cc6bd798da7'
self.git_remote = "origin"
self.git_remote_url = "https://git.sickrage.ca/SiCKRAGE/sickrage"
self.unrar_tool = rarfile.UNRAR_TOOL
self.naming_force_folders = False
self.min_auto_postprocessor_freq = 1
self.min_daily_searcher_freq = 10
self.min_backlog_searcher_freq = 10
self.min_version_updater_freq = 1
self.min_subtitle_searcher_freq = 1
self.min_failed_snatch_age = 1
try:
self.tz = tz.tzwinlocal() if tz.tzwinlocal else tz.tzlocal()
except Exception:
self.tz = tz.tzlocal()
self.shows = {}
self.shows_recent = deque(maxlen=5)
self.main_db = None
self.cache_db = None
self.config_file = None
self.data_dir = None
self.cache_dir = None
self.quiet = None
self.no_launch = None
self.disable_updates = None
self.web_port = None
self.web_host = None
self.web_root = None
self.developer = None
self.db_type = None
self.db_prefix = None
self.db_host = None
self.db_port = None
self.db_username = None
self.db_password = None
self.debug = None
self.latest_version_string = None
self.naming_ep_type = (
"%(seasonnumber)dx%(episodenumber)02d",
"s%(seasonnumber)02de%(episodenumber)02d",
"S%(seasonnumber)02dE%(episodenumber)02d",
"%(seasonnumber)02dx%(episodenumber)02d",
"S%(seasonnumber)02d E%(episodenumber)02d"
)
self.sports_ep_type = (
"%(seasonnumber)dx%(episodenumber)02d",
"s%(seasonnumber)02de%(episodenumber)02d",
"S%(seasonnumber)02dE%(episodenumber)02d",
"%(seasonnumber)02dx%(episodenumber)02d",
"S%(seasonnumber)02 dE%(episodenumber)02d"
)
self.naming_ep_type_text = (
"1x02",
"s01e02",
"S01E02",
"01x02",
"S01 E02"
)
self.naming_multi_ep_type = {
0: ["-%(episodenumber)02d"] * len(self.naming_ep_type),
1: [" - " + x for x in self.naming_ep_type],
2: [x + "%(episodenumber)02d" for x in ("x", "e", "E", "x")]
}
self.naming_multi_ep_type_text = (
"extend",
"duplicate",
"repeat"
)
self.naming_sep_type = (
" - ",
" "
)
self.naming_sep_type_text = (
" - ",
"space"
)
self.user_agent = 'SiCKRAGE.CE.1/({};{};{})'.format(platform.system(), platform.release(), str(uuid.uuid1()))
self.languages = [f for f in os.listdir(sickrage.LOCALE_DIR) if os.path.isdir(os.path.join(sickrage.LOCALE_DIR, f))]
self.client_web_urls = {'torrent': '', 'newznab': ''}
self.notification_providers = {}
self.metadata_providers = {}
self.search_providers = {}
self.series_providers = {}
self.adba_connection = None
self.log = None
self.config = None
self.alerts = None
self.scheduler = None
self.wserver = None
self.google_auth = None
self.show_queue = None
self.search_queue = None
self.postprocessor_queue = None
self.version_updater = None
self.show_updater = None
self.tz_updater = None
self.rsscache_updater = None
self.daily_searcher = None
self.failed_snatch_searcher = None
self.backlog_searcher = None
self.proper_searcher = None
self.trakt_searcher = None
self.subtitle_searcher = None
self.auto_postprocessor = None
self.upnp_client = None
self.auto_backup = None
self.auth_server = None
self.announcements = None
self.api = None
self.amqp_consumer = None
def start(self):
self.started = True
# thread name
threading.current_thread().name = 'CORE'
# set event loop policy
asyncio.set_event_loop_policy(AnyThreadEventLoopPolicy())
# init sentry
self.init_sentry()
# scheduler
self.scheduler = TornadoScheduler({'apscheduler.timezone': 'UTC'})
# init core classes
self.api = API()
self.config = Config(self.db_type, self.db_prefix, self.db_host, self.db_port, self.db_username, self.db_password)
self.main_db = MainDB(self.db_type, self.db_prefix, self.db_host, self.db_port, self.db_username, self.db_password)
self.cache_db = CacheDB(self.db_type, self.db_prefix, self.db_host, self.db_port, self.db_username, self.db_password)
self.notification_providers = NotificationProviders()
self.metadata_providers = MetadataProviders()
self.search_providers = SearchProviders()
self.series_providers = SeriesProviders()
self.log = Logger(consoleLogging=not self.quiet, logFile=os.path.join(self.data_dir, 'logs', 'sickrage.log'))
self.alerts = Notifications()
self.wserver = WebServer()
self.show_queue = ShowQueue()
self.search_queue = SearchQueue()
self.postprocessor_queue = PostProcessorQueue()
self.version_updater = VersionUpdater()
self.show_updater = ShowUpdater()
self.tz_updater = TimeZoneUpdater()
self.rsscache_updater = RSSCacheUpdater()
self.daily_searcher = DailySearcher()
self.failed_snatch_searcher = FailedSnatchSearcher()
self.backlog_searcher = BacklogSearcher()
self.proper_searcher = ProperSearcher()
self.trakt_searcher = TraktSearcher()
self.subtitle_searcher = SubtitleSearcher()
self.auto_postprocessor = AutoPostProcessor()
self.upnp_client = UPNPClient()
self.auto_backup = AutoBackup()
self.announcements = Announcements()
self.amqp_consumer = AMQPConsumer()
# authorization sso client
self.auth_server = AuthServer()
# check available space
try:
self.log.info("Performing disk space checks")
total_space, available_space = get_free_space(self.data_dir)
if available_space < 100:
self.log.warning('Shutting down as SiCKRAGE needs some space to work. You\'ll get corrupted data otherwise. Only %sMB left', available_space)
return
except Exception:
self.log.error('Failed getting disk space: %s', traceback.format_exc())
# check if we need to perform a restore first
if os.path.exists(os.path.abspath(os.path.join(self.data_dir, 'restore'))):
self.log.info('Performing restore of backup files')
success = restore_app_data(os.path.abspath(os.path.join(self.data_dir, 'restore')), self.data_dir)
self.log.info("Restoring SiCKRAGE backup: %s!" % ("FAILED", "SUCCESSFUL")[success])
if success:
# remove restore files
shutil.rmtree(os.path.abspath(os.path.join(self.data_dir, 'restore')), ignore_errors=True)
# migrate old database file names to new ones
if os.path.isfile(os.path.abspath(os.path.join(self.data_dir, 'sickbeard.db'))):
if os.path.isfile(os.path.join(self.data_dir, 'sickrage.db')):
helpers.move_file(os.path.join(self.data_dir, 'sickrage.db'),
os.path.join(self.data_dir, '{}.bak-{}'
.format('sickrage.db',
datetime.datetime.now().strftime(
'%Y%m%d_%H%M%S'))))
helpers.move_file(os.path.abspath(os.path.join(self.data_dir, 'sickbeard.db')),
os.path.abspath(os.path.join(self.data_dir, 'sickrage.db')))
# setup databases
self.main_db.setup()
self.config.db.setup()
self.cache_db.setup()
# load config
self.config.load()
# migrate config
self.config.migrate_config_file(self.config_file)
# add server id tag to sentry
sentry_sdk.set_tag('server_id', self.config.general.server_id)
# add user to sentry
sentry_sdk.set_user({
'id': self.config.user.sub_id,
'username': self.config.user.username,
'email': self.config.user.email
})
# config overrides
if self.web_port:
self.config.general.web_port = self.web_port
if self.web_root:
self.config.general.web_root = self.web_root
# set language
change_gui_lang(self.config.gui.gui_lang)
# set socket timeout
socket.setdefaulttimeout(self.config.general.socket_timeout)
# setup logger settings
self.log.logSize = self.config.general.log_size
self.log.logNr = self.config.general.log_nr
self.log.debugLogging = self.debug or self.config.general.debug
# start logger
self.log.start()
# user agent
if self.config.general.random_user_agent:
self.user_agent = UserAgent().random
uses_netloc.append('scgi')
FancyURLopener.version = self.user_agent
# set torrent client web url
torrent_webui_url(True)
if self.config.general.default_page not in DefaultHomePage:
self.config.general.default_page = DefaultHomePage.HOME
# attempt to help prevent users from breaking links by using a bad url
if not self.config.general.anon_redirect.endswith('?'):
self.config.general.anon_redirect = ''
if not re.match(r'\d+\|[^|]+(?:\|[^|]+)*', self.config.general.root_dirs):
self.config.general.root_dirs = ''
self.naming_force_folders = check_force_season_folders()
if self.config.general.nzb_method not in NzbMethod:
self.config.general.nzb_method = NzbMethod.BLACKHOLE
if self.config.general.torrent_method not in TorrentMethod:
self.config.general.torrent_method = TorrentMethod.BLACKHOLE
if self.config.general.auto_postprocessor_freq < self.min_auto_postprocessor_freq:
self.config.general.auto_postprocessor_freq = self.min_auto_postprocessor_freq
if self.config.general.daily_searcher_freq < self.min_daily_searcher_freq:
self.config.general.daily_searcher_freq = self.min_daily_searcher_freq
if self.config.general.backlog_searcher_freq < self.min_backlog_searcher_freq:
self.config.general.backlog_searcher_freq = self.min_backlog_searcher_freq
if self.config.general.version_updater_freq < self.min_version_updater_freq:
self.config.general.version_updater_freq = self.min_version_updater_freq
if self.config.general.subtitle_searcher_freq < self.min_subtitle_searcher_freq:
self.config.general.subtitle_searcher_freq = self.min_subtitle_searcher_freq
if self.config.failed_snatches.age < self.min_failed_snatch_age:
self.config.failed_snatches.age = self.min_failed_snatch_age
if self.config.general.proper_searcher_interval not in CheckPropersInterval:
self.config.general.proper_searcher_interval = CheckPropersInterval.DAILY
if self.config.general.show_update_hour < 0 or self.config.general.show_update_hour > 23:
self.config.general.show_update_hour = 0
# add app updater job
self.scheduler.add_job(
self.version_updater.task,
IntervalTrigger(
hours=1,
start_date=datetime.datetime.now() + datetime.timedelta(minutes=4),
timezone='utc'
),
name=self.version_updater.name,
id=self.version_updater.name
)
# add show updater job
self.scheduler.add_job(
self.show_updater.task,
IntervalTrigger(
days=1,
start_date=datetime.datetime.now().replace(hour=self.config.general.show_update_hour),
timezone='utc'
),
name=self.show_updater.name,
id=self.show_updater.name
)
# add rss cache updater job
self.scheduler.add_job(
self.rsscache_updater.task,
IntervalTrigger(
minutes=15,
timezone='utc'
),
name=self.rsscache_updater.name,
id=self.rsscache_updater.name
)
# add daily search job
self.scheduler.add_job(
self.daily_searcher.task,
IntervalTrigger(
minutes=self.config.general.daily_searcher_freq,
start_date=datetime.datetime.now() + datetime.timedelta(minutes=4),
timezone='utc'
),
name=self.daily_searcher.name,
id=self.daily_searcher.name
)
# add failed snatch search job
self.scheduler.add_job(
self.failed_snatch_searcher.task,
IntervalTrigger(
hours=1,
start_date=datetime.datetime.now() + datetime.timedelta(minutes=4),
timezone='utc'
),
name=self.failed_snatch_searcher.name,
id=self.failed_snatch_searcher.name
)
# add backlog search job
self.scheduler.add_job(
self.backlog_searcher.task,
IntervalTrigger(
minutes=self.config.general.backlog_searcher_freq,
start_date=datetime.datetime.now() + datetime.timedelta(minutes=30),
timezone='utc'
),
name=self.backlog_searcher.name,
id=self.backlog_searcher.name
)
# add auto-postprocessing job
self.scheduler.add_job(
self.auto_postprocessor.task,
IntervalTrigger(
minutes=self.config.general.auto_postprocessor_freq,
timezone='utc'
),
name=self.auto_postprocessor.name,
id=self.auto_postprocessor.name
)
# add find proper job
self.scheduler.add_job(
self.proper_searcher.task,
IntervalTrigger(minutes=self.config.general.proper_searcher_interval.value, timezone='utc'),
name=self.proper_searcher.name,
id=self.proper_searcher.name
)
# add trakt.tv checker job
self.scheduler.add_job(
self.trakt_searcher.task,
IntervalTrigger(
hours=1,
timezone='utc'
),
name=self.trakt_searcher.name,
id=self.trakt_searcher.name
)
# add subtitles finder job
self.scheduler.add_job(
self.subtitle_searcher.task,
IntervalTrigger(
hours=self.config.general.subtitle_searcher_freq,
timezone='utc'
),
name=self.subtitle_searcher.name,
id=self.subtitle_searcher.name
)
# add upnp client job
self.scheduler.add_job(
self.upnp_client.task,
IntervalTrigger(
seconds=self.upnp_client._nat_portmap_lifetime,
timezone='utc'
),
name=self.upnp_client.name,
id=self.upnp_client.name
)
# add auto backup job
self.scheduler.add_job(
self.auto_backup.task,
IntervalTrigger(
hours=self.config.general.auto_backup_freq,
timezone='utc'
),
name=self.auto_backup.name,
id=self.auto_backup.name
)
# start queues
self.search_queue.start_worker(self.config.general.max_queue_workers)
self.show_queue.start_worker(self.config.general.max_queue_workers)
self.postprocessor_queue.start_worker(self.config.general.max_queue_workers)
# start web server
self.wserver.start()
# start scheduler service
self.scheduler.start()
# perform server checkup
IOLoop.current().add_callback(self.server_checkup)
# load shows
IOLoop.current().add_callback(self.load_shows)
# perform version update check
IOLoop.current().spawn_callback(self.version_updater.check_for_update)
# load network timezones
IOLoop.current().spawn_callback(self.tz_updater.update_network_timezones)
# load search provider urls
IOLoop.current().spawn_callback(self.search_providers.update_urls)
# startup message
IOLoop.current().add_callback(self.startup_message)
# launch browser
IOLoop.current().add_callback(self.launch_browser)
# watch websocket message queue
PeriodicCallback(check_web_socket_queue, 100).start()
# perform server checkups every hour
PeriodicCallback(self.server_checkup, 1 * 60 * 60 * 1000).start()
# perform shutdown trigger check every 5 seconds
PeriodicCallback(self.shutdown_trigger, 5 * 1000).start()
def init_sentry(self):
# sentry log handler
sentry_logging = LoggingIntegration(
level=logging.INFO, # Capture info and above as breadcrumbs
event_level=logging.ERROR # Send errors as events
)
# init sentry logging
sentry_sdk.init(
dsn="https://d4bf4ed225c946c8972c7238ad07d124@sentry.sickrage.ca/2?verify_ssl=0",
integrations=[sentry_logging],
release=sickrage.version(),
environment=('master', 'develop')['dev' in sickrage.version()],
ignore_errors=[
'KeyboardInterrupt',
'PermissionError',
'FileNotFoundError',
'EpisodeNotFoundException'
]
)
# sentry tags
sentry_tags = {
'platform': platform.platform(),
'locale': repr(locale.getdefaultlocale()),
'python': platform.python_version(),
'install_type': sickrage.install_type()
}
# set sentry tags
for tag_key, tag_value in sentry_tags.items():
sentry_sdk.set_tag(tag_key, tag_value)
# set loggers to ignore
ignored_loggers = [
'enzyme.parsers.ebml.core',
'subliminal.core',
'subliminal.utils',
'subliminal.refiners.tvdb',
'subliminal.refiners.metadata',
'subliminal.providers.tvsubtitles',
'pika.connection',
'pika.adapters.base_connection',
'pika.adapters.utils.io_services_utils',
'pika.adapters.utils.connection_workflow',
'pika.adapters.utils.selector_ioloop_adapter'
]
for item in ignored_loggers:
ignore_logger(item)
def server_checkup(self):
if self.config.general.server_id:
server_status = self.api.server.get_status(self.config.general.server_id)
if server_status and not server_status['registered']:
# re-register server
server_id = self.api.server.register_server(
ip_addresses=','.join([get_internal_ip()]),
web_protocol=('http', 'https')[self.config.general.enable_https],
web_port=self.config.general.web_port,
web_root=self.config.general.web_root,
server_version=sickrage.version(),
)
if server_id:
self.log.info('Re-registered SiCKRAGE server with SiCKRAGE API')
sentry_sdk.set_tag('server_id', self.config.general.server_id)
self.config.general.server_id = server_id
self.config.save(mark_dirty=True)
else:
self.log.debug('Updating SiCKRAGE server data on SiCKRAGE API')
# update server information
self.api.server.update_server(
server_id=self.config.general.server_id,
ip_addresses=','.join([get_internal_ip()]),
web_protocol=('http', 'https')[self.config.general.enable_https],
web_port=self.config.general.web_port,
web_root=self.config.general.web_root,
server_version=sickrage.version(),
)
def load_shows(self):
threading.current_thread().name = 'CORE'
session = self.main_db.session()
self.log.info('Loading initial shows list')
self.loading_shows = True
self.shows = {}
for query in session.query(MainDB.TVShow).with_entities(MainDB.TVShow.series_id, MainDB.TVShow.series_provider_id, MainDB.TVShow.name,
MainDB.TVShow.location):
try:
# if not os.path.isdir(query.location) and self.config.general.create_missing_show_dirs:
# make_dir(query.location)
self.log.info('Loading show {}'.format(query.name))
self.shows.update({(query.series_id, query.series_provider_id): TVShow(query.series_id, query.series_provider_id)})
except Exception as e:
self.log.debug('There was an error loading show: {}'.format(query.name))
self.loading_shows = False
self.log.info('Loading initial shows list finished')
def startup_message(self):
self.log.info("SiCKRAGE :: STARTED")
self.log.info(f"SiCKRAGE :: APP VERSION:[{sickrage.version()}]")
self.log.info(f"SiCKRAGE :: CONFIG VERSION:[v{self.config.db.version}]")
self.log.info(f"SiCKRAGE :: DATABASE VERSION:[v{self.main_db.version}]")
self.log.info(f"SiCKRAGE :: DATABASE TYPE:[{self.db_type}]")
self.log.info(f"SiCKRAGE :: INSTALL TYPE:[{self.version_updater.updater.type}]")
self.log.info(
f"SiCKRAGE :: URL:[{('http', 'https')[self.config.general.enable_https]}://{(get_internal_ip(), self.web_host)[self.web_host not in ['', '0.0.0.0']]}:{self.config.general.web_port}/{self.config.general.web_root.lstrip('/')}]")
def launch_browser(self):
if not self.no_launch and self.config.general.launch_browser:
launch_browser(protocol=('http', 'https')[self.config.general.enable_https],
host=(get_internal_ip(), self.web_host)[self.web_host != ''],
startport=self.config.general.web_port)
def shutdown(self, restart=False):
if self.started:
self.log.info('SiCKRAGE IS {}!!!'.format(('SHUTTING DOWN', 'RESTARTING')[restart]))
# shutdown scheduler
if self.scheduler:
try:
self.scheduler.shutdown()
except (SchedulerNotRunningError, RuntimeError):
pass
# shutdown webserver
if self.wserver:
self.wserver.shutdown()
# stop queues
self.search_queue.shutdown()
self.show_queue.shutdown()
self.postprocessor_queue.shutdown()
# stop amqp consumer
self.amqp_consumer.stop()
# log out of ADBA
if self.adba_connection:
self.log.debug("Shutting down ANIDB connection")
self.adba_connection.stop()
# save shows
self.log.info('Saving all shows to the database')
for show in self.shows.values():
show.save()
# save settings
self.config.save()
# shutdown databases
self.main_db.shutdown()
self.config.db.shutdown()
self.cache_db.shutdown()
# shutdown logging
if self.log:
self.log.close()
if restart:
os.execl(sys.executable, sys.executable, *sys.argv)
if self.daemon:
self.daemon.stop()
self.started = False
def restart(self):
self.shutdown(restart=True)
def shutdown_trigger(self):
if not self.started:
IOLoop.current().stop()
================================================
FILE: sickrage/core/amqp/__init__.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import ssl
import pika
from pika.adapters.tornado_connection import TornadoConnection
from pika.adapters.utils.connection_workflow import AMQPConnectorException
from pika.exceptions import StreamLostError, AMQPConnectionError, ChannelWrongStateError
from tornado.ioloop import IOLoop
import sickrage
class AMQPBase(object):
def __init__(self):
self._name = 'AMQP'
self._amqp_host = 'rmq.sickrage.ca'
self._amqp_port = 5671
self._amqp_vhost = 'sickrage-app'
self._connection = None
self._channel = None
self._closing = False
self._consumer_tag = None
self._prefetch_count = 100
IOLoop.current().add_callback(self.connect)
def connect(self):
# check for api token
if not sickrage.app.api.token or not sickrage.app.config.general.server_id:
IOLoop.current().call_later(5, self.reconnect)
return
# declare server amqp queue
if not sickrage.app.api.server.declare_amqp_queue(sickrage.app.config.general.server_id):
IOLoop.current().call_later(5, self.reconnect)
return
# connect to amqp server
try:
credentials = pika.credentials.PlainCredentials(username='sickrage', password=sickrage.app.api.token["access_token"])
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
parameters = pika.ConnectionParameters(
host=self._amqp_host,
port=self._amqp_port,
virtual_host=self._amqp_vhost,
credentials=credentials,
socket_timeout=300,
ssl_options=pika.SSLOptions(context)
)
TornadoConnection(
parameters,
on_open_callback=self.on_connection_open,
on_close_callback=self.on_connection_close,
on_open_error_callback=self.on_connection_open_error
)
except (AMQPConnectorException, AMQPConnectionError):
sickrage.app.log.debug("AMQP connection error, attempting to reconnect")
IOLoop.current().call_later(5, self.reconnect)
def disconnect(self):
if self._channel and not self._channel.is_closed:
try:
self._channel.close()
except (ChannelWrongStateError, StreamLostError):
pass
if self._connection and not self._connection.is_closed:
try:
self._connection.close()
except (ChannelWrongStateError, StreamLostError):
pass
self._channel = None
self._connection = None
def on_connection_close(self, connection, reason):
if not self._closing:
sickrage.app.log.debug("AMQP connection closed, attempting to reconnect")
IOLoop.current().call_later(5, self.reconnect)
def on_connection_open(self, connection):
self._connection = connection
self._connection.channel(on_open_callback=self.on_channel_open)
def on_connection_open_error(self, connection, reason):
sickrage.app.log.debug("AMQP connection open failed, attempting to reconnect")
IOLoop.current().call_later(5, self.reconnect)
def reconnect(self):
if not self._closing:
self.connect()
def on_channel_open(self, channel):
self._channel = channel
def stop(self):
self._closing = True
self.disconnect()
================================================
FILE: sickrage/core/amqp/consumer.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
from google.protobuf.json_format import MessageToDict
from pika.exceptions import ChannelWrongStateError, StreamLostError
from tornado.ioloop import IOLoop
import sickrage
from sickrage.core.amqp import AMQPBase
from sickrage.core.amqp.protos.announcement_v1_pb2 import CreatedAnnouncementResponse, DeletedAnnouncementResponse
from sickrage.core.amqp.protos.network_timezone_v1_pb2 import SavedNetworkTimezoneResponse, DeletedNetworkTimezoneResponse
from sickrage.core.amqp.protos.search_provider_url_v1_pb2 import SavedSearchProviderUrlResponse
from sickrage.core.amqp.protos.server_certificate_v1_pb2 import SavedServerCertificateResponse
from sickrage.core.amqp.protos.updates_v1_pb2 import UpdatedAppResponse
class AMQPConsumer(AMQPBase):
def __init__(self):
super(AMQPConsumer, self).__init__()
@property
def events(self):
return {
'server_ssl_certificate.saved': {
'event_msg': SavedServerCertificateResponse(),
'event_cmd': sickrage.app.wserver.load_ssl_certificate,
},
'network_timezone.saved': {
'event_msg': SavedNetworkTimezoneResponse(),
'event_cmd': sickrage.app.tz_updater.update_network_timezone,
},
'network_timezone.deleted': {
'event_msg': DeletedNetworkTimezoneResponse(),
'event_cmd': sickrage.app.tz_updater.delete_network_timezone,
},
'search_provider_url.saved': {
'event_msg': SavedSearchProviderUrlResponse(),
'event_cmd': sickrage.app.search_providers.update_url,
},
'app.updated': {
'event_msg': UpdatedAppResponse(),
'event_cmd': sickrage.app.version_updater.task,
},
'announcement.created': {
'event_msg': CreatedAnnouncementResponse(),
'event_cmd': sickrage.app.announcements.add,
},
'announcement.deleted': {
'event_msg': DeletedAnnouncementResponse(),
'event_cmd': sickrage.app.announcements.clear,
},
}
def on_channel_open(self, channel):
self._channel = channel
self._channel.basic_qos(callback=self.on_qos_applied, prefetch_count=self._prefetch_count)
def on_qos_applied(self, method):
self.start_consuming()
def on_message(self, unused_channel, basic_deliver, properties, body):
try:
if basic_deliver.exchange in self.events:
event = self.events[basic_deliver.exchange]
message = event['event_msg']
message.ParseFromString(body)
message_kwargs = MessageToDict(message, including_default_value_fields=True, preserving_proto_field_name=True)
sickrage.app.log.debug(
f"Received AMQP event: {basic_deliver.exchange} :: {message_kwargs!r}"
)
IOLoop.current().spawn_callback(event['event_cmd'], **message_kwargs)
except Exception as e:
sickrage.app.log.debug(f"AMQP exchange: {basic_deliver.exchange} message caused an exception: {e!r}")
finally:
self._channel.basic_ack(basic_deliver.delivery_tag)
def start_consuming(self):
sickrage.app.log.info('Connected to SiCKRAGE AMQP server')
try:
self._consumer_tag = self._channel.basic_consume(
on_message_callback=self.on_message,
queue=f'{sickrage.app.config.user.sub_id}.{sickrage.app.config.general.server_id}',
)
except (ChannelWrongStateError, StreamLostError):
sickrage.app.log.debug('AMQP channel error, attempting to reconnect')
IOLoop.current().call_later(5, self.reconnect)
================================================
FILE: sickrage/core/amqp/protos/announcement_v1_pb2.py
================================================
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: announcement_v1.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x61nnouncement_v1.proto\x12\x10\x61pp.protobufs.v1\"m\n\x1b\x43reatedAnnouncementResponse\x12\r\n\x05\x61hash\x18\x01 \x01(\t\x12\r\n\x05title\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\r\n\x05image\x18\x04 \x01(\t\x12\x0c\n\x04\x64\x61te\x18\x05 \x01(\t\",\n\x1b\x44\x65letedAnnouncementResponse\x12\r\n\x05\x61hash\x18\x01 \x01(\tb\x06proto3')
_CREATEDANNOUNCEMENTRESPONSE = DESCRIPTOR.message_types_by_name['CreatedAnnouncementResponse']
_DELETEDANNOUNCEMENTRESPONSE = DESCRIPTOR.message_types_by_name['DeletedAnnouncementResponse']
CreatedAnnouncementResponse = _reflection.GeneratedProtocolMessageType('CreatedAnnouncementResponse', (_message.Message,), {
'DESCRIPTOR' : _CREATEDANNOUNCEMENTRESPONSE,
'__module__' : 'announcement_v1_pb2'
# @@protoc_insertion_point(class_scope:app.protobufs.v1.CreatedAnnouncementResponse)
})
_sym_db.RegisterMessage(CreatedAnnouncementResponse)
DeletedAnnouncementResponse = _reflection.GeneratedProtocolMessageType('DeletedAnnouncementResponse', (_message.Message,), {
'DESCRIPTOR' : _DELETEDANNOUNCEMENTRESPONSE,
'__module__' : 'announcement_v1_pb2'
# @@protoc_insertion_point(class_scope:app.protobufs.v1.DeletedAnnouncementResponse)
})
_sym_db.RegisterMessage(DeletedAnnouncementResponse)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
_CREATEDANNOUNCEMENTRESPONSE._serialized_start=43
_CREATEDANNOUNCEMENTRESPONSE._serialized_end=152
_DELETEDANNOUNCEMENTRESPONSE._serialized_start=154
_DELETEDANNOUNCEMENTRESPONSE._serialized_end=198
# @@protoc_insertion_point(module_scope)
================================================
FILE: sickrage/core/amqp/protos/network_timezone_v1_pb2.py
================================================
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: network_timezone_v1.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19network_timezone_v1.proto\x12\x10\x61pp.protobufs.v1\"A\n\x1cSavedNetworkTimezoneResponse\x12\x0f\n\x07network\x18\x01 \x01(\t\x12\x10\n\x08timezone\x18\x02 \x01(\t\"1\n\x1e\x44\x65letedNetworkTimezoneResponse\x12\x0f\n\x07network\x18\x01 \x01(\tb\x06proto3')
_SAVEDNETWORKTIMEZONERESPONSE = DESCRIPTOR.message_types_by_name['SavedNetworkTimezoneResponse']
_DELETEDNETWORKTIMEZONERESPONSE = DESCRIPTOR.message_types_by_name['DeletedNetworkTimezoneResponse']
SavedNetworkTimezoneResponse = _reflection.GeneratedProtocolMessageType('SavedNetworkTimezoneResponse', (_message.Message,), {
'DESCRIPTOR' : _SAVEDNETWORKTIMEZONERESPONSE,
'__module__' : 'network_timezone_v1_pb2'
# @@protoc_insertion_point(class_scope:app.protobufs.v1.SavedNetworkTimezoneResponse)
})
_sym_db.RegisterMessage(SavedNetworkTimezoneResponse)
DeletedNetworkTimezoneResponse = _reflection.GeneratedProtocolMessageType('DeletedNetworkTimezoneResponse', (_message.Message,), {
'DESCRIPTOR' : _DELETEDNETWORKTIMEZONERESPONSE,
'__module__' : 'network_timezone_v1_pb2'
# @@protoc_insertion_point(class_scope:app.protobufs.v1.DeletedNetworkTimezoneResponse)
})
_sym_db.RegisterMessage(DeletedNetworkTimezoneResponse)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
_SAVEDNETWORKTIMEZONERESPONSE._serialized_start=47
_SAVEDNETWORKTIMEZONERESPONSE._serialized_end=112
_DELETEDNETWORKTIMEZONERESPONSE._serialized_start=114
_DELETEDNETWORKTIMEZONERESPONSE._serialized_end=163
# @@protoc_insertion_point(module_scope)
================================================
FILE: sickrage/core/amqp/protos/search_provider_url_v1_pb2.py
================================================
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: search_provider_url_v1.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1csearch_provider_url_v1.proto\x12\x10\x61pp.protobufs.v1\"K\n\x1eSavedSearchProviderUrlResponse\x12\x13\n\x0bprovider_id\x18\x01 \x01(\t\x12\x14\n\x0cprovider_url\x18\x02 \x01(\tb\x06proto3')
_SAVEDSEARCHPROVIDERURLRESPONSE = DESCRIPTOR.message_types_by_name['SavedSearchProviderUrlResponse']
SavedSearchProviderUrlResponse = _reflection.GeneratedProtocolMessageType('SavedSearchProviderUrlResponse', (_message.Message,), {
'DESCRIPTOR' : _SAVEDSEARCHPROVIDERURLRESPONSE,
'__module__' : 'search_provider_url_v1_pb2'
# @@protoc_insertion_point(class_scope:app.protobufs.v1.SavedSearchProviderUrlResponse)
})
_sym_db.RegisterMessage(SavedSearchProviderUrlResponse)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
_SAVEDSEARCHPROVIDERURLRESPONSE._serialized_start=50
_SAVEDSEARCHPROVIDERURLRESPONSE._serialized_end=125
# @@protoc_insertion_point(module_scope)
================================================
FILE: sickrage/core/amqp/protos/server_certificate_v1_pb2.py
================================================
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: server_certificate_v1.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1bserver_certificate_v1.proto\x12\x10\x61pp.protobufs.v1\"J\n\x1eSavedServerCertificateResponse\x12\x13\n\x0b\x63\x65rtificate\x18\x01 \x01(\t\x12\x13\n\x0bprivate_key\x18\x02 \x01(\tb\x06proto3')
_SAVEDSERVERCERTIFICATERESPONSE = DESCRIPTOR.message_types_by_name['SavedServerCertificateResponse']
SavedServerCertificateResponse = _reflection.GeneratedProtocolMessageType('SavedServerCertificateResponse', (_message.Message,), {
'DESCRIPTOR' : _SAVEDSERVERCERTIFICATERESPONSE,
'__module__' : 'server_certificate_v1_pb2'
# @@protoc_insertion_point(class_scope:app.protobufs.v1.SavedServerCertificateResponse)
})
_sym_db.RegisterMessage(SavedServerCertificateResponse)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
_SAVEDSERVERCERTIFICATERESPONSE._serialized_start=49
_SAVEDSERVERCERTIFICATERESPONSE._serialized_end=123
# @@protoc_insertion_point(module_scope)
================================================
FILE: sickrage/core/amqp/protos/updates_v1_pb2.py
================================================
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: updates_v1.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10updates_v1.proto\x12\x10\x61pp.protobufs.v1\"#\n\x12UpdatedAppResponse\x12\r\n\x05\x66orce\x18\x01 \x01(\x08\x62\x06proto3')
_UPDATEDAPPRESPONSE = DESCRIPTOR.message_types_by_name['UpdatedAppResponse']
UpdatedAppResponse = _reflection.GeneratedProtocolMessageType('UpdatedAppResponse', (_message.Message,), {
'DESCRIPTOR' : _UPDATEDAPPRESPONSE,
'__module__' : 'updates_v1_pb2'
# @@protoc_insertion_point(class_scope:app.protobufs.v1.UpdatedAppResponse)
})
_sym_db.RegisterMessage(UpdatedAppResponse)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
_UPDATEDAPPRESPONSE._serialized_start=38
_UPDATEDAPPRESPONSE._serialized_end=73
# @@protoc_insertion_point(module_scope)
================================================
FILE: sickrage/core/announcements.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import functools
import threading
from sqlalchemy import orm
import sickrage
from sickrage.core.databases.cache import CacheDB
class Announcement(object):
"""
Represents an announcement.
"""
def __init__(self, title, description, image, date, ahash):
self.title = title
self.description = description
self.image = image
self.date = date
self.ahash = ahash
@property
def seen(self):
session = sickrage.app.cache_db.session()
try:
announcement = session.query(CacheDB.Announcements).filter_by(hash=self.ahash).one()
return True if announcement.seen else False
except orm.exc.NoResultFound:
pass
@seen.setter
def seen(self, value):
session = sickrage.app.cache_db.session()
try:
announcement = session.query(CacheDB.Announcements).filter_by(hash=self.ahash).one()
announcement.seen = value
except orm.exc.NoResultFound:
pass
class Announcements(object):
"""
Keeps a static list of (announcement) UIErrors to be displayed on the UI and allows
the list to be cleared.
"""
def __init__(self):
self.name = "ANNOUNCEMENTS"
self.running = False
self._announcements = {}
def add(self, ahash, title, description, image, date):
session = sickrage.app.cache_db.session()
self._announcements[ahash] = Announcement(title, description, image, date, ahash)
if not session.query(CacheDB.Announcements).filter_by(hash=ahash).count():
sickrage.app.log.debug('Adding new announcement to Web-UI')
session.add(CacheDB.Announcements(**{'hash': ahash}))
session.commit()
def clear(self, ahash=None):
session = sickrage.app.cache_db.session()
if not ahash:
self._announcements.clear()
session.query(CacheDB.Announcements).delete()
session.commit()
else:
if ahash in self._announcements:
del self._announcements[ahash]
session.query(CacheDB.Announcements).filter_by(hash=ahash).delete()
session.commit()
def get_all(self):
return sorted(self._announcements.values(), key=lambda k: k.date)
def get(self, ahash):
return self._announcements.get(ahash)
def count(self):
session = sickrage.app.cache_db.session()
return session.query(CacheDB.Announcements).filter(CacheDB.Announcements.seen is False).count()
================================================
FILE: sickrage/core/api/__init__.py
================================================
import collections
import errno
import time
import traceback
from urllib.parse import urljoin
import oauthlib.oauth2
import requests
import requests.exceptions
from jose import ExpiredSignatureError
from keycloak.exceptions import KeycloakClientError
from requests_oauthlib import OAuth2Session
import sickrage
from sickrage.core.api.exceptions import APIError
class API(object):
def __init__(self):
self.name = 'SR-API'
self.api_base = 'https://www.sickrage.ca/api/'
self.api_version = 'v6'
self._token = {}
@property
def imdb(self):
return self.IMDbAPI(self)
@property
def server(self):
return self.ServerAPI(self)
@property
def search_provider(self):
return self.SearchProviderAPI(self)
@property
def series_provider(self):
return self.SeriesProviderAPI(self)
@property
def announcement(self):
return self.AnnouncementsAPI(self)
@property
def google(self):
return self.GoogleDriveAPI(self)
@property
def torrent(self):
return self.TorrentAPI(self)
@property
def scene_exceptions(self):
return self.SceneExceptions(self)
@property
def alexa(self):
return self.AlexaAPI(self)
@property
def session(self):
if not self.token_url:
return
return OAuth2Session(
token=self.token,
auto_refresh_kwargs={'client_id': sickrage.app.auth_server.client_id},
auto_refresh_url=self.token_url,
token_updater=self.token_updater
)
@property
def token(self):
if not self._token:
self.login()
elif self.token_time_remaining < (int(self._token.get('expires_in')) / 2):
self.refresh_token()
return self._token
@property
def token_expiration(self):
try:
if not self._token:
return time.time()
certs = sickrage.app.auth_server.certs()
if not certs:
return time.time()
decoded_token = sickrage.app.auth_server.decode_token(self._token.get('access_token'), certs)
return decoded_token.get('exp', time.time())
except ExpiredSignatureError:
return time.time()
@property
def token_time_remaining(self):
return max(self.token_expiration - time.time(), 0)
@property
def token_is_expired(self):
return self.token_expiration <= time.time()
@property
def token_url(self):
return sickrage.app.auth_server.get_url('token_endpoint')
@property
def health(self):
for i in range(3):
try:
health = requests.get(urljoin(self.api_base, "health"), verify=True, timeout=30).ok
except (requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout):
pass
else:
break
else:
health = False
if not health:
sickrage.app.log.debug("SiCKRAGE API is currently unreachable")
return False
return True
@property
def userinfo(self):
return self.request('GET', 'userinfo')
def token_updater(self, value):
self._token = value
def login(self):
if not self.health:
return False
if not self.token_url:
return False
session = requests.session()
data = {
'client_id': sickrage.app.auth_server.client_id,
'grant_type': 'password',
'apikey': sickrage.app.config.general.sso_api_key
}
try:
resp = session.post(self.token_url, data)
resp.raise_for_status()
self._token = resp.json()
except requests.exceptions.RequestException:
return False
return True
def logout(self):
if self._token:
try:
sickrage.app.auth_server.logout(self._token.get('refresh_token'))
except KeycloakClientError:
pass
def refresh_token(self):
retries = 3
for i in range(retries):
try:
if not self._token:
return self.login()
self._token = sickrage.app.auth_server.refresh_token(self._token.get('refresh_token'))
except KeycloakClientError:
return self.login()
except (requests.exceptions.ReadTimeout, requests.exceptions.ConnectionError):
if i > retries:
return False
time.sleep(0.2)
continue
return True
def allowed_usernames(self):
return self.request('GET', 'allowed-usernames')
def download_privatekey(self):
return self.request('GET', 'server/config/private-key')
def upload_privatekey(self, privatekey):
return self.request('POST', 'server/config/private-key', data=dict({'privatekey': privatekey}))
def network_timezones(self):
return self.request('GET', 'network-timezones')
def request(self, method, url, timeout=120, **kwargs):
if not self.session:
return
url = urljoin(self.api_base, "/".join([self.api_version, url]))
for i in range(5):
resp = None
try:
if not self.health:
if i > 3:
return None
continue
resp = self.session.request(method, url, timeout=timeout, verify=False, hooks={'response': self.throttle_hook}, **kwargs)
resp.raise_for_status()
if resp.status_code == 204:
return resp.ok
try:
return resp.json()
except ValueError:
return resp.content
except (oauthlib.oauth2.TokenExpiredError, oauthlib.oauth2.InvalidGrantError):
self.refresh_token()
time.sleep(1)
except (oauthlib.oauth2.InvalidClientIdError, oauthlib.oauth2.MissingTokenError) as e:
self.refresh_token()
time.sleep(1)
except requests.exceptions.ReadTimeout as e:
if i > 3:
sickrage.app.log.debug(f'Error connecting to url {url} Error: {e}')
return resp or e.response
timeout += timeout
time.sleep(1)
except requests.exceptions.HTTPError as e:
status_code = e.response.status_code
error_message = e.response.text
if status_code == 403 and "login-pf-page" in error_message:
self.refresh_token()
time.sleep(1)
continue
if 'application/json' in e.response.headers.get('content-type', ''):
status_code = e.response.json().get('error', status_code)
error_message = e.response.json().get('message', error_message)
sickrage.app.log.debug(f'SiCKRAGE API response returned for url {url} Response: {error_message}, Code: {status_code}')
else:
sickrage.app.log.debug(f'The response returned a non-200 response while requesting url {url} Error: {e!r}')
return resp or e.response
except requests.exceptions.ConnectionError as e:
if i > 3:
sickrage.app.log.debug(f'Error connecting to url {url} Error: {e}')
return resp or e.response
time.sleep(1)
except requests.exceptions.RequestException as e:
sickrage.app.log.debug(f'Error requesting url {url} Error: {e}')
return resp or e.response
except Exception as e:
if (isinstance(e, collections.Iterable) and 'ECONNRESET' in e) or (getattr(e, 'errno', None) == errno.ECONNRESET):
sickrage.app.log.warning(f'Connection reset by peer accessing url {url} Error: {e}')
else:
sickrage.app.log.info(f'Unknown exception in url {url} Error: {e}')
sickrage.app.log.debug(traceback.format_exc())
return None
@staticmethod
def throttle_hook(response, **kwargs):
if "X-RateLimit-Remaining" in response.headers:
remaining = int(response.headers["X-RateLimit-Remaining"])
if remaining == 1:
sickrage.app.log.debug("Throttling SiCKRAGE API Calls... Sleeping for 60 secs...\n")
time.sleep(60)
class ServerAPI:
def __init__(self, api):
self.api = api
def register_server(self, ip_addresses, web_protocol, web_port, web_root, server_version):
data = {
'ip-addresses': ip_addresses,
'web-protocol': web_protocol,
'web-port': web_port,
'web-root': web_root,
'server-version': server_version
}
return self.api.request('POST', 'server', data=data)
def unregister_server(self, server_id):
data = {
'server-id': server_id
}
return self.api.request('DELETE', 'server', data=data)
def update_server(self, server_id, ip_addresses, web_protocol, web_port, web_root, server_version):
data = {
'server-id': server_id,
'ip-addresses': ip_addresses,
'web-protocol': web_protocol,
'web-port': web_port,
'web-root': web_root,
'server-version': server_version
}
return self.api.request('PUT', 'server', data=data)
def get_status(self, server_id):
return self.api.request('GET', f'server/{server_id}/status')
def get_server_certificate(self, server_id):
return self.api.request('GET', f'server/{server_id}/certificate')
def declare_amqp_queue(self, server_id):
return self.api.request('GET', f'server/{server_id}/declare-amqp-queue')
def upload_config(self, server_id, pkey_sig, config):
data = {
'server-id': server_id,
'pkey-sig': pkey_sig,
'config': config
}
return self.api.request('POST', f'server/{server_id}/config', data=data)
def download_config(self, server_id, pkey_sig):
data = {
'pkey-sig': pkey_sig
}
return self.api.request('GET', f'server/{server_id}/config', json=data)['config']
class AnnouncementsAPI:
def __init__(self, api):
self.api = api
def get_announcements(self):
return self.api.request('GET', 'announcements')
class SearchProviderAPI:
def __init__(self, api):
self.api = api
def get_url(self, provider):
endpoint = f'provider/{provider}/url'
return self.api.request('GET', endpoint)
def get_status(self, provider):
endpoint = f'provider/{provider}/status'
return self.api.request('GET', endpoint)
def get_search_result(self, provider, series_id, season, episode):
endpoint = f'provider/{provider}/series-id/{series_id}/season/{season}/episode/{episode}'
return self.api.request('GET', endpoint)
def add_search_result(self, provider, data):
return self.api.request('POST', f'provider/{provider}', json=data)
class TorrentAPI:
def __init__(self, api):
self.api = api
def get_trackers(self):
endpoint = f'torrent/trackers'
return self.api.request('GET', endpoint)
def get_torrent(self, hash):
endpoint = f'torrent/{hash}'
return self.api.request('GET', endpoint)
def add_torrent(self, url):
return self.api.request('POST', 'torrent', json={'url': url})
class IMDbAPI:
def __init__(self, api):
self.api = api
def search_by_imdb_title(self, title):
endpoint = f'imdb/search-by-title/{title}'
return self.api.request('GET', endpoint)
def search_by_imdb_id(self, imdb_id):
endpoint = f'imdb/search-by-id/{imdb_id}'
return self.api.request('GET', endpoint)
class GoogleDriveAPI:
def __init__(self, api):
self.api = api
def is_connected(self):
endpoint = 'google-drive/is-connected'
return self.api.request('GET', endpoint)
def upload(self, file, folder):
endpoint = 'google-drive/upload'
return self.api.request('POST', endpoint, files={'file': open(file, 'rb')}, params={'folder': folder})
def download(self, id):
endpoint = f'google-drive/download/{id}'
return self.api.request('GET', endpoint)
def delete(self, id):
endpoint = f'google-drive/delete/{id}'
return self.api.request('GET', endpoint)
def search_files(self, id, term):
endpoint = f'google-drive/search-files/{id}/{term}'
return self.api.request('GET', endpoint)
def list_files(self, id):
endpoint = f'google-drive/list-files/{id}'
return self.api.request('GET', endpoint)
def clear_folder(self, id):
endpoint = f'google-drive/clear-folder/{id}'
return self.api.request('GET', endpoint)
class SceneExceptions:
def __init__(self, api):
self.api = api
def get(self, *args, **kwargs):
endpoint = 'scene-exceptions'
return self.api.request('GET', endpoint)
def search_by_id(self, series_id):
endpoint = f'scene-exceptions/search-by-id/{series_id}'
return self.api.request('GET', endpoint)
class AlexaAPI:
def __init__(self, api):
self.api = api
def send_notification(self, message):
return self.api.request('POST', 'alexa/notification', json={'message': message})
class SeriesProviderAPI:
def __init__(self, api):
self.api = api
def search(self, provider, query, language='eng'):
endpoint = f'series-provider/{provider}/search/{query}/{language}'
return self.api.request('GET', endpoint)
def search_by_id(self, provider, remote_id, language='eng'):
endpoint = f'series-provider/{provider}/search-by-id/{remote_id}/{language}'
return self.api.request('GET', endpoint)
def get_series_info(self, provider, series_id, language='eng'):
endpoint = f'series-provider/{provider}/series/{series_id}/{language}'
return self.api.request('GET', endpoint)
def get_episodes_info(self, provider, series_id, season_type='default', language='eng'):
endpoint = f'series-provider/{provider}/series/{series_id}/episodes/{season_type}/{language}'
return self.api.request('GET', endpoint)
def languages(self, provider):
endpoint = f'series-provider/{provider}/languages'
return self.api.request('GET', endpoint)
def updates(self, provider, since):
endpoint = f'series-provider/{provider}/updates/{since}'
return self.api.request('GET', endpoint)
================================================
FILE: sickrage/core/api/exceptions.py
================================================
class APIError(Exception):
"""
API Error
"""
def __init__(self, status, message, response):
self._status = status
self._message = message
self._response = response
@property
def status(self):
return self._status
@property
def message(self):
return self._message
@property
def response(self):
return self._response
def __unicode__(self):
return self.__class__.__name__ + ': ' + self.message
def __repr__(self):
return self.__unicode__()
class APIResourceDoesNotExist(APIError):
"""Custom exception when resource is not found."""
pass
class APIUnauthorized(APIError):
"""Need JWT Token"""
pass
class APITokenExpired(APIError):
"""JWT Token Expired"""
pass
================================================
FILE: sickrage/core/auth/__init__.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import requests
from keycloak.exceptions import KeycloakClientError
from keycloak.openid_connect import KeycloakOpenidConnect
from keycloak.realm import KeycloakRealm
import sickrage
class KeycloakOpenidConnectCustom(KeycloakOpenidConnect):
def get_path_well_known(self):
return "realms/{}/.well-known/openid-configuration"
class AuthServer(object):
__server = {}
__client = {}
def __init__(self):
self.server_url = 'https://auth.sickrage.ca'
self.server_realm = 'sickrage'
self.client_id = 'sickrage-app'
self._certs = None
@property
def client(self):
return self.__get_client()
@property
def health(self):
for i in range(3):
try:
health = requests.get("{base}/realms/{realm}".format(base=self.server_url, realm=self.server_realm), verify=False, timeout=30).ok
except (requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout):
pass
else:
break
else:
health = False
if not health:
sickrage.app.log.debug("SiCKRAGE authorization server is currently unreachable")
return False
return True
def get_url(self, *args, **kwargs):
try:
return self.client.get_url(*args, **kwargs)
except (KeycloakClientError, requests.exceptions.ConnectionError) as e:
return
def certs(self):
try:
if not self._certs and self.health:
self._certs = self.client.certs()
return self._certs
except requests.exceptions.ConnectionError as e:
return
def logout(self, *args, **kwargs):
if not self.health:
return
return self.client.logout(*args, **kwargs)
def decode_token(self, *args, **kwargs):
return self.client.decode_token(*args, **kwargs, audience='sickrage-api')
def refresh_token(self, *args, **kwargs):
if not self.health:
return
return self.client.refresh_token(*args, **kwargs)
def authorization_code(self, *args, **kwargs):
if not self.health:
return
return self.client.authorization_code(*args, **kwargs)
def authorization_url(self, **kwargs):
if not self.health:
return
return self.client.authorization_url(**kwargs)
def token_exchange(self, access_token, scope='offline_access'):
if not self.health:
return
exchange = {'scope': scope, 'subject_token': access_token}
return self.client.token_exchange(**exchange)
def __get_client(self) -> KeycloakOpenidConnect:
client = self.__client.get('client', None)
if client is None:
self.__client.update({'client': KeycloakOpenidConnectCustom(self.__get_server(), self.client_id, '')})
client = self.__client.get('client', None)
return client
def __get_server(self) -> KeycloakRealm:
server = self.__server.get('server', None)
if server is None:
self.__server.update({'server': KeycloakRealm(server_url=self.server_url, realm_name=self.server_realm)})
server = self.__server.get('server', None)
return server
================================================
FILE: sickrage/core/auto_backup.py
================================================
import sickrage
from sickrage.core.helpers import backup_app_data
class AutoBackup(object):
def __init__(self, *args, **kwargs):
self.name = "AUTO-BACKUP"
def task(self):
if not sickrage.app.config.general.auto_backup_enable:
return
sickrage.app.log.info("Performing automatic backup of SiCKRAGE")
backup_app_data(sickrage.app.config.general.auto_backup_dir, backup_type="auto", keep_num=sickrage.app.config.general.auto_backup_keep_num)
sickrage.app.log.info("Finished automatic backup of SiCKRAGE")
================================================
FILE: sickrage/core/blackandwhitelist.py
================================================
# Author: Dennis Lutter
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
#
# This file is part of SiCKRAGE.
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Sick Beard 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
import sickrage
from sickrage.core.databases.main import MainDB
class BlackAndWhiteList(object):
blacklist = []
whitelist = []
def __init__(self, series_id, series_provider_id):
if not series_id:
raise BlackWhitelistNoShowIDException()
self.series_id = series_id
self.series_provider_id = series_provider_id
self.load()
def load(self):
"""
Builds black and whitelist
"""
session = sickrage.app.main_db.session()
sickrage.app.log.debug('Building black and white list for ' + str(self.series_id))
self.blacklist = self._load_list(session.query(MainDB.Blacklist).filter_by(series_id=self.series_id, series_provider_id=self.series_provider_id))
sickrage.app.log.debug('BWL: {} loaded keywords from {}: {}'.format(self.series_id, MainDB.Blacklist.__tablename__, self.blacklist))
self.whitelist = self._load_list(session.query(MainDB.Whitelist).filter_by(series_id=self.series_id, series_provider_id=self.series_provider_id))
sickrage.app.log.debug('BWL: {} loaded keywords from {}: {}'.format(self.series_id, MainDB.Whitelist.__tablename__, self.whitelist))
def _add_keywords(self, table, values):
"""
DB: Adds keywords into database for current show
:param table: database table to add keywords to
:param values: Values to be inserted in table
"""
session = sickrage.app.main_db.session()
for value in values:
session.add(table(**{
'series_id': self.series_id,
'series_provider_id': self.series_provider_id,
'keyword': value
}))
session.commit()
def set_black_keywords(self, values):
"""
Sets blacklist to new value
:param values: Complete list of keywords to be set as blacklist
:param session: Database session
"""
session = sickrage.app.main_db.session()
session.query(MainDB.Blacklist).filter_by(series_id=self.series_id, series_provider_id=self.series_provider_id).delete()
session.commit()
self._add_keywords(MainDB.Blacklist, values)
self.blacklist = values
sickrage.app.log.debug('Blacklist set to: %s' % self.blacklist)
def set_white_keywords(self, values):
"""
Sets whitelist to new value
:param values: Complete list of keywords to be set as whitelist
:param session: Database session
"""
session = sickrage.app.main_db.session()
session.query(MainDB.Whitelist).filter_by(series_id=self.series_id, series_provider_id=self.series_provider_id).delete()
session.commit()
self._add_keywords(MainDB.Whitelist, values)
self.whitelist = values
sickrage.app.log.debug('Whitelist set to: %s' % self.whitelist)
def _load_list(self, keyword_list):
"""
DB: Fetch keywords for current show
:return: keywords in list
"""
try:
groups = [x.keyword for x in keyword_list]
except KeyError:
groups = []
return groups
def is_valid(self, result):
"""
Check if result is valid according to white/blacklist for current show
:param result: Result to analyse
:return: False if result is not allowed in white/blacklist, True if it is
"""
if self.whitelist or self.blacklist:
if not result.release_group:
sickrage.app.log.debug('Failed to detect release group')
return False
if result.release_group.lower() in [x.lower() for x in self.whitelist]:
white_result = True
elif not self.whitelist:
white_result = True
else:
white_result = False
if result.release_group.lower() in [x.lower() for x in self.blacklist]:
black_result = False
else:
black_result = True
sickrage.app.log.debug(
'Whitelist check passed: %s. Blacklist check passed: %s' % (white_result, black_result))
if white_result and black_result:
return True
else:
return False
else:
sickrage.app.log.debug('No Whitelist and Blacklist defined')
return True
class BlackWhitelistNoShowIDException(Exception):
"""No series_id was given"""
================================================
FILE: sickrage/core/caches/__init__.py
================================================
# import os
#
# from dogpile.cache import make_region
# from dogpile.cache.backends.file import AbstractFileLock
# from dogpile.util import ReadWriteMutex
#
#
# class MutexLock(AbstractFileLock):
# """:class:`MutexLock` is a thread-based rw lock based on :class:`dogpile.core.ReadWriteMutex`."""
#
# def __init__(self, filename):
# """Constructor.
# :param filename:
# """
# self.mutex = ReadWriteMutex()
#
# def acquire_read_lock(self, wait):
# """Default acquire_read_lock."""
# ret = self.mutex.acquire_read_lock(wait)
# return wait or ret
#
# def acquire_write_lock(self, wait):
# """Default acquire_write_lock."""
# ret = self.mutex.acquire_write_lock(wait)
# return wait or ret
#
# def release_read_lock(self):
# """Default release_read_lock."""
# return self.mutex.release_read_lock()
#
# def release_write_lock(self):
# """Default release_write_lock."""
# return self.mutex.release_write_lock()
#
#
# def configure_regions(cache_dir, replace_existing_backend=False):
# tv_episodes_cache.configure('dogpile.cache.dbm', replace_existing_backend=replace_existing_backend,
# arguments={'filename': os.path.join(cache_dir, 'tv_episodes.dbm'), 'lock_factory': MutexLock})
#
#
# tv_episodes_cache = make_region()
================================================
FILE: sickrage/core/caches/image_cache.py
================================================
# Author: echel0n
# URL: https://sickrage.ca
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
#
# This file is part of SiCKRAGE.
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
import os
from hachoir.core import config as hachoir_config
import sickrage
from sickrage.core.helpers import copy_file
from sickrage.metadata_providers import MetadataProvider
class ImageCache(object):
BANNER = 1
POSTER = 2
BANNER_THUMB = 3
POSTER_THUMB = 4
FANART = 5
FANART_THUMB = 6
IMAGE_TYPES = {
BANNER: 'banner',
POSTER: 'poster',
BANNER_THUMB: 'banner_thumb',
POSTER_THUMB: 'poster_thumb',
FANART: 'fanart',
FANART_THUMB: 'fanart_thumb'
}
def __init__(self):
hachoir_config.quiet = True
def __del__(self):
pass
def _cache_dir(self):
"""
Builds up the full path to the image cache directory
"""
return os.path.abspath(os.path.join(sickrage.app.cache_dir, 'images'))
def _cache_series_dir(self, series_id):
"""
Builds up the full path to the image cache directory
"""
return os.path.abspath(os.path.join(self._cache_dir(), 'series', str(series_id)))
def _cache_seasons_dir(self, series_id):
"""
Builds up the full path to the image cache directory
"""
return os.path.abspath(os.path.join(self._cache_series_dir(series_id), 'seasons'))
def _cache_episodes_dir(self, series_id):
"""
Builds up the full path to the image cache directory
"""
return os.path.abspath(os.path.join(self._cache_series_dir(series_id), 'episodes'))
def _thumbnails_dir(self):
"""
Builds up the full path to the thumbnails image cache directory
"""
return os.path.abspath(os.path.join(self._cache_dir(), 'thumbnails'))
def poster_path(self, series_id, season_id=None, episode_id=None):
"""
Builds up the path to a poster cache for a given series id
:param series_id: ID of the show to use in the file name
:return: a full path to the cached poster file for the given series id
"""
if episode_id:
poster_file_name = str(episode_id) + '.poster.jpg'
return os.path.join(self._cache_episodes_dir(series_id), poster_file_name)
elif season_id:
poster_file_name = str(season_id) + '.poster.jpg'
return os.path.join(self._cache_seasons_dir(series_id), poster_file_name)
else:
poster_file_name = str(series_id) + '.poster.jpg'
return os.path.join(self._cache_dir(), poster_file_name)
def banner_path(self, series_id, season_id=None, episode_id=None):
"""
Builds up the path to a banner cache for a given series id
:param series_id: ID of the show to use in the file name
:return: a full path to the cached banner file for the given series id
"""
banner_file_name = str(series_id) + '.banner.jpg'
return os.path.join(self._cache_dir(), banner_file_name)
def fanart_path(self, series_id, season_id=None, episode_id=None):
"""
Builds up the path to a fanart cache for a given series id
:param series_id: ID of the show to use in the file name
:return: a full path to the cached fanart file for the given series id
"""
fanart_file_name = str(series_id) + '.fanart.jpg'
return os.path.join(self._cache_dir(), fanart_file_name)
def fanart_thumb_path(self, series_id, season_id=None, episode_id=None):
"""
Builds up the path to a poster thumb cache for a given series id
:param series_id: ID of the show to use in the file name
:return: a full path to the cached poster thumb file for the given series id
"""
fanartthumb_file_name = str(series_id) + '.fanart.jpg'
return os.path.join(self._thumbnails_dir(), fanartthumb_file_name)
def poster_thumb_path(self, series_id, season_id=None, episode_id=None):
"""
Builds up the path to a poster thumb cache for a given series id
:param series_id: ID of the show to use in the file name
:return: a full path to the cached poster thumb file for the given series id
"""
posterthumb_file_name = str(series_id) + '.poster.jpg'
return os.path.join(self._thumbnails_dir(), posterthumb_file_name)
def banner_thumb_path(self, series_id, season_id=None, episode_id=None):
"""
Builds up the path to a banner thumb cache for a given series id
:param series_id: ID of the show to use in the file name
:return: a full path to the cached banner thumb file for the given series id
"""
bannerthumb_file_name = str(series_id) + '.banner.jpg'
return os.path.join(self._thumbnails_dir(), bannerthumb_file_name)
def has_poster(self, series_id, season_id=None, episode_id=None):
"""
Returns true if a cached poster exists for the given series/season/episode id
"""
poster_path = self.poster_path(series_id, season_id, episode_id)
sickrage.app.log.debug("Checking if file " + str(poster_path) + " exists")
return os.path.isfile(poster_path)
def has_banner(self, series_id, season_id=None, episode_id=None):
"""
Returns true if a cached banner exists for the given series id
"""
banner_path = self.banner_path(series_id)
sickrage.app.log.debug("Checking if file " + str(banner_path) + " exists")
return os.path.isfile(banner_path)
def has_fanart(self, series_id, season_id=None, episode_id=None):
"""
Returns true if a cached fanart exists for the given series id
"""
fanart_path = self.fanart_path(series_id)
sickrage.app.log.debug("Checking if file " + str(fanart_path) + " exists")
return os.path.isfile(fanart_path)
def has_poster_thumbnail(self, series_id, season_id=None, episode_id=None):
"""
Returns true if a cached poster thumbnail exists for the given series id
"""
poster_thumb_path = self.poster_thumb_path(series_id)
sickrage.app.log.debug("Checking if file " + str(poster_thumb_path) + " exists")
return os.path.isfile(poster_thumb_path)
def has_banner_thumbnail(self, series_id, season_id=None, episode_id=None):
"""
Returns true if a cached banner exists for the given series id
"""
banner_thumb_path = self.banner_thumb_path(series_id)
sickrage.app.log.debug("Checking if file " + str(banner_thumb_path) + " exists")
return os.path.isfile(banner_thumb_path)
def which_type(self, path):
"""
Analyzes the image provided and attempts to determine whether it is a poster or banner.
:param path: full path to the image
:return: BANNER, POSTER if it concluded one or the other, or None if the image was neither (or didn't exist)
"""
if not os.path.isfile(path):
sickrage.app.log.warning("Couldn't check the type of " + str(path) + " cause it doesn't exist")
return None
from hachoir.metadata import extractMetadata
from hachoir.parser import guessParser
from hachoir.stream import StringInputStream
with open(path, 'rb') as fh:
img_metadata = extractMetadata(guessParser(StringInputStream(fh.read())))
if not img_metadata:
sickrage.app.log.debug(
"Unable to get metadata from " + str(path) + ", not using your existing image")
return None
img_ratio = float(img_metadata.get('width', 0)) / float(img_metadata.get('height', 0))
# most posters are around 0.68 width/height ratio (eg. 680/1000)
if 0.55 < img_ratio < 0.8:
return self.POSTER
# most banners are around 5.4 width/height ratio (eg. 758/140)
elif 5 < img_ratio < 6:
return self.BANNER
# most fanart are around 1.77777 width/height ratio (eg. 1280/720 and 1920/1080)
elif 1.7 < img_ratio < 1.8:
return self.FANART
else:
sickrage.app.log.warning("Image has size ratio of " + str(img_ratio) + ", unknown type")
def _cache_image_from_file(self, image_path, img_type, series_id):
"""
Takes the image provided and copies it to the cache folder
:param image_path: path to the image we're caching
:param img_type: BANNER or POSTER or FANART
:param series_id: id of the show this image belongs to
:return: bool representing success
"""
# generate the path based on the type & series_id
if img_type == self.POSTER:
dest_path = self.poster_path(series_id)
elif img_type == self.BANNER:
dest_path = self.banner_path(series_id)
elif img_type == self.FANART:
dest_path = self.fanart_path(series_id)
else:
sickrage.app.log.error("Invalid cache image type: " + str(img_type))
return False
# make sure the cache folder exists before we try copying to it
if not os.path.isdir(self._cache_dir()):
sickrage.app.log.info("Image cache dir didn't exist, creating it at " + str(self._cache_dir()))
os.makedirs(self._cache_dir())
if not os.path.isdir(self._thumbnails_dir()):
sickrage.app.log.info(
"Thumbnails cache dir didn't exist, creating it at " + str(self._thumbnails_dir()))
os.makedirs(self._thumbnails_dir())
sickrage.app.log.info("Copying from " + image_path + " to " + dest_path)
copy_file(image_path, dest_path)
return True
def _cache_image_from_series_provider(self, show_obj, img_type, force=False):
"""
Retrieves an image of the type specified from a series provider and saves it to the cache folder
:param show_obj: TVShow object that we want to cache an image for
:param img_type: BANNER or POSTER or FANART
:return: bool representing success
"""
# generate the path based on the type & series_id
if img_type == self.POSTER:
dest_path = self.poster_path(show_obj.series_id)
elif img_type == self.BANNER:
dest_path = self.banner_path(show_obj.series_id)
elif img_type == self.FANART:
dest_path = self.fanart_path(show_obj.series_id)
elif img_type == self.POSTER_THUMB:
dest_path = self.poster_thumb_path(show_obj.series_id)
elif img_type == self.BANNER_THUMB:
dest_path = self.banner_thumb_path(show_obj.series_id)
elif img_type == self.FANART_THUMB:
dest_path = self.fanart_thumb_path(show_obj.series_id)
else:
sickrage.app.log.error("Invalid cache image type: {}".format(img_type))
return False
# retrieve series and season images from a series provider
metadata_generator = MetadataProvider()
img_data = metadata_generator._retrieve_show_image(self.IMAGE_TYPES[img_type], show_obj)
if not img_data:
return False
result = metadata_generator._write_image(img_data, dest_path, force)
return result
def _cache_episode_images_from_series_provider(self, show_obj, force=False):
"""
Retrieves episode images from a series provider and saves it to the cache folder
:param show_obj: TVShow object that we want to cache an image for
:return: bool representing success
"""
metadata_generator = MetadataProvider()
# retrieve episode images from a series provider
series_provider_language = show_obj.lang or sickrage.app.config.general.series_provider_default_language
series_info = show_obj.series_provider.get_series_info(show_obj.series_id, language=series_provider_language)
if not series_info:
return False
for episode in show_obj.episodes:
series_episode = series_info[episode.season][episode.episode]
img_data = metadata_generator.get_image(series_episode.imageUrl)
if img_data:
dest_path = self.poster_path(show_obj.series_id, episode_id=series_episode.id)
metadata_generator._write_image(img_data, dest_path, force)
def fill_cache(self, show_obj, force=False):
"""
Caches all images for the given show. Copies them from the show dir if possible, or
downloads them from a series provider if they aren't in the show dir.
:param show_obj: TVShow object to cache images for
"""
sickrage.app.log.debug("Checking if we need any cache images for show " + str(show_obj.series_id))
# check if the images are already cached or not
need_images = {self.POSTER: force or not self.has_poster(show_obj.series_id),
self.BANNER: force or not self.has_banner(show_obj.series_id),
self.POSTER_THUMB: force or not self.has_poster_thumbnail(show_obj.series_id),
self.BANNER_THUMB: force or not self.has_banner_thumbnail(show_obj.series_id),
self.FANART: force or not self.has_fanart(show_obj.series_id)}
if all([not need_images[self.POSTER],
not need_images[self.BANNER],
not need_images[self.POSTER_THUMB],
not need_images[self.BANNER_THUMB],
not need_images[self.FANART]]):
sickrage.app.log.debug("No new cache images needed, not retrieving new ones")
return
# check the show dir for poster or banner images and use them
if any([need_images[self.POSTER], need_images[self.BANNER], need_images[self.FANART]]):
if os.path.isdir(show_obj.location):
for cur_provider in sickrage.app.metadata_providers.values():
sickrage.app.log.debug(
"Checking if we can use the show image from the " + cur_provider.name + " metadata")
if os.path.isfile(cur_provider.get_poster_path(show_obj)):
cur_file_name = os.path.abspath(cur_provider.get_poster_path(show_obj))
cur_file_type = self.which_type(cur_file_name)
if cur_file_type is None:
sickrage.app.log.warning(
"Unable to retrieve image type {}, not using the image from {}".format(
str(cur_file_type), cur_file_name))
continue
sickrage.app.log.debug("Checking if image " + cur_file_name + " (type " + str(
cur_file_type) + " needs metadata: " + str(need_images[cur_file_type]))
if cur_file_type in need_images and need_images[cur_file_type]:
sickrage.app.log.debug(f"Found an image in the show dir that doesn't exist in the cache, caching it: {cur_file_name}, type {cur_file_type}")
self._cache_image_from_file(cur_file_name, cur_file_type, show_obj.series_id)
need_images[cur_file_type] = False
# download missing series and season images from a series provider
for cur_image_type in [self.POSTER, self.BANNER, self.POSTER_THUMB, self.BANNER_THUMB, self.FANART]:
sickrage.app.log.debug(f"Seeing if we still need an image of type {cur_image_type}: {need_images[cur_image_type]}")
if cur_image_type in need_images and need_images[cur_image_type]:
self._cache_image_from_series_provider(show_obj, cur_image_type, force)
# download missing episode images from a series provider
sickrage.app.log.debug(f"Seeing if we still need episode poster images")
for episode in show_obj.episodes:
if not self.has_poster(show_obj.series_id, episode_id=episode.episode_id):
self._cache_episode_images_from_series_provider(show_obj, force)
sickrage.app.log.info("Done cache check")
================================================
FILE: sickrage/core/caches/name_cache.py
================================================
# Author: echel0n
# URL: https://sickrage.ca
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
#
# This file is part of SiCKRAGE.
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
import threading
import time
from datetime import datetime, timedelta
from sqlalchemy import orm
import sickrage
from sickrage.core.databases.cache import CacheDB
from sickrage.core.helpers import full_sanitize_scene_name
class NameCache(object):
def __init__(self, *args, **kwargs):
self.name = "NAMECACHE"
self.running = False
self.min_time = 10
self.last_update = {}
self.cache = {}
def should_update(self, show):
# if we've updated recently then skip the update
if datetime.today() - (self.last_update.get(show.name) or datetime.fromtimestamp(
int(time.mktime(datetime.today().timetuple())))) < timedelta(minutes=self.min_time):
return True
def put(self, name, series_id=0):
"""
Adds the show & tvdb id to the scene_names table in cache db
:param name: The show name to cache
:param series_id: the TVDB id that this show should be cached with (can be None/0 for unknown)
"""
session = sickrage.app.cache_db.session()
# standardize the name we're using to account for small differences in providers
name = full_sanitize_scene_name(name)
self.cache[name] = int(series_id)
try:
session.query(CacheDB.SceneName).filter_by(name=name, series_id=int(series_id)).one()
except orm.exc.NoResultFound:
session.add(CacheDB.SceneName(**{
'series_id': series_id,
'name': name
}))
finally:
session.commit()
def get(self, name):
"""
Looks up the given name in the scene_names table in cache db
:param name: The show name to look up.
:return: the TVDB id that resulted from the cache lookup or None if the show wasn't found in the cache
"""
name = full_sanitize_scene_name(name)
if name in self.cache:
return int(self.cache[name])
def clear(self, series_id=None, name=None):
"""
Deletes all entries from the cache matching the series_id or name.
"""
session = sickrage.app.cache_db.session()
if any([series_id, name]):
if series_id:
session.query(CacheDB.SceneName).filter_by(series_id=series_id).delete()
session.commit()
elif name:
session.query(CacheDB.SceneName).filter_by(name=name).delete()
session.commit()
for key, value in self.cache.copy().items():
if value == series_id or key == name:
del self.cache[key]
def load(self):
session = sickrage.app.cache_db.session()
self.cache = dict([(x.name, x.series_id) for x in session.query(CacheDB.SceneName)])
def save(self):
"""
Commit cache to database file
"""
session = sickrage.app.cache_db.session()
sql_t = []
for name, series_id in self.cache.items():
try:
session.query(CacheDB.SceneName).filter_by(name=name, series_id=series_id).one()
except orm.exc.NoResultFound:
sql_t.append({
'series_id': series_id,
'name': name
})
session.bulk_insert_mappings(CacheDB.SceneName, sql_t)
session.commit()
================================================
FILE: sickrage/core/caches/tv_cache.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import datetime
import threading
import time
import feedparser
from sqlalchemy import orm
from sqlalchemy.exc import IntegrityError
import sickrage
from sickrage.core.common import Quality, Qualities
from sickrage.core.databases.cache import CacheDB
from sickrage.core.enums import SeriesProviderID
from sickrage.core.exceptions import AuthException
from sickrage.core.helpers import show_names, try_int
from sickrage.core.nameparser import InvalidNameException, NameParser, InvalidShowException
from sickrage.core.tv.show.helpers import find_show
from sickrage.core.websession import WebSession
class TVCache(object):
def __init__(self, provider, **kwargs):
self.lock = threading.Lock()
self.provider = provider
self.providerID = self.provider.id
self.min_time = kwargs.pop('min_time', 10)
self.search_strings = kwargs.pop('search_strings', dict(RSS=['']))
def clear(self):
session = sickrage.app.cache_db.session()
if self.shouldClearCache():
session.query(CacheDB.Provider).filter_by(provider=self.providerID).delete()
session.commit()
def _get_title_and_url(self, item):
return self.provider._get_title_and_url(item)
def _get_result_stats(self, item):
return self.provider._get_result_stats(item)
def _get_size(self, item):
return self.provider._get_size(item)
def _get_rss_data(self):
if self.search_strings:
return {'entries': self.provider.search(self.search_strings)}
def _check_auth(self, data):
return True
def check_item(self, title, url):
return True
def update(self, force=False):
# check if we should update
if self.should_update() or force:
try:
data = self._get_rss_data()
if not self._check_auth(data):
return False
# clear cache
self.clear()
# set updated
self.last_update = datetime.datetime.today()
[self._parseItem(item) for item in data['entries']]
sickrage.app.log.debug("Updated RSS cache")
except AuthException as e:
sickrage.app.log.warning("Authentication error: {}".format(e))
return False
except Exception as e:
sickrage.app.log.debug("Error while searching {}, skipping: {}".format(self.provider.name, repr(e)))
return False
return True
def get_rss_feed(self, url, params=None):
try:
if self.provider.login():
resp = WebSession().get(url, timeout=30, params=params)
if resp:
return feedparser.parse(resp.text)
except Exception as e:
sickrage.app.log.debug("RSS Error: {}".format(e))
return feedparser.FeedParserDict()
def _translateTitle(self, title):
return '' + title.replace(' ', '.')
def _translateLinkURL(self, url):
return url.replace('&', '&')
def _parseItem(self, item):
title, url = self._get_title_and_url(item)
seeders, leechers = self._get_result_stats(item)
size = self._get_size(item)
self.check_item(title, url)
if title and url:
self.add_cache_entry(self._translateTitle(title), self._translateLinkURL(url), seeders, leechers, size)
else:
sickrage.app.log.debug(
"The data returned from the " + self.provider.name + " feed is incomplete, this result is unusable")
@property
def last_update(self):
session = sickrage.app.cache_db.session()
try:
dbData = session.query(CacheDB.LastUpdate).filter_by(provider=self.providerID).one()
lastTime = int(dbData.time)
if lastTime > int(time.mktime(datetime.datetime.today().timetuple())):
lastTime = 0
except orm.exc.NoResultFound:
lastTime = 0
return datetime.datetime.fromtimestamp(lastTime)
@last_update.setter
def last_update(self, toDate):
session = sickrage.app.cache_db.session()
with self.lock:
try:
dbData = session.query(CacheDB.LastUpdate).filter_by(provider=self.providerID).one()
dbData.time = int(time.mktime(toDate.timetuple()))
except orm.exc.NoResultFound:
session.add(CacheDB.LastUpdate(**{
'provider': self.providerID,
'time': int(time.mktime(toDate.timetuple()))
}))
finally:
session.commit()
@property
def last_search(self):
session = sickrage.app.cache_db.session()
try:
dbData = session.query(CacheDB.LastSearch).filter_by(provider=self.providerID).one()
lastTime = int(dbData.time)
if lastTime > int(time.mktime(datetime.datetime.today().timetuple())):
lastTime = 0
except orm.exc.NoResultFound:
lastTime = 0
return datetime.datetime.fromtimestamp(lastTime)
@last_search.setter
def last_search(self, toDate):
session = sickrage.app.cache_db.session()
with self.lock:
try:
dbData = session.query(CacheDB.LastSearch).filter_by(provider=self.providerID).one()
dbData.time = int(time.mktime(toDate.timetuple()))
except orm.exc.NoResultFound:
session.add(CacheDB.LastSearch(**{
'provider': self.providerID,
'time': int(time.mktime(toDate.timetuple()))
}))
finally:
session.commit()
def should_update(self):
# if we've updated recently then skip the update
if datetime.datetime.today() - self.last_update < datetime.timedelta(minutes=self.min_time):
return False
return True
def shouldClearCache(self):
# if daily search hasn't used our previous results yet then don't clear the cache
if self.last_update > self.last_search:
return False
return True
def add_cache_entry(self, name, url, seeders, leechers, size):
session = sickrage.app.cache_db.session()
# check for existing entry in cache
if session.query(CacheDB.Provider).filter_by(url=url).count():
return
try:
# parse release name
parse_result = NameParser(validate_show=True).parse(name)
if parse_result.series_name and parse_result.quality != Qualities.UNKNOWN:
season = parse_result.season_number if parse_result.season_number else 1
episodes = parse_result.episode_numbers
if season and episodes:
# store episodes as a seperated string
episode_text = "|" + "|".join(map(str, episodes)) + "|"
# get quality of release
quality = parse_result.quality
# get release group
release_group = parse_result.release_group
# get version
version = parse_result.version
dbData = {
'provider': self.providerID,
'name': name,
'season': season,
'episodes': episode_text,
'series_id': parse_result.series_id,
'series_provider_id': parse_result.series_provider_id.name,
'url': url,
'time': int(time.mktime(datetime.datetime.today().timetuple())),
'quality': quality,
'release_group': release_group,
'version': version,
'seeders': try_int(seeders),
'leechers': try_int(leechers),
'size': try_int(size, -1)
}
# add to internal database
try:
session.add(CacheDB.Provider(**dbData))
session.commit()
sickrage.app.log.debug("SEARCH RESULT:[{}] ADDED TO CACHE!".format(name))
except IntegrityError:
pass
# add to external provider cache database
if sickrage.app.config.general.enable_sickrage_api:
from sickrage.search_providers import SearchProviderType
if not self.provider.private and self.provider.provider_type in [SearchProviderType.NZB, SearchProviderType.TORRENT]:
try:
sickrage.app.api.search_provider.add_search_result(provider=self.providerID, data=dbData)
except Exception as e:
pass
except (InvalidShowException, InvalidNameException):
pass
def search_cache(self, series_id, series_provider_id, season, episode, manualSearch=False, downCurQuality=False):
cache_results = {}
dbData = []
# get data from external database
if sickrage.app.config.general.enable_sickrage_api and not self.provider.private:
resp = sickrage.app.api.search_provider.get_search_result(self.providerID, series_id, season, episode)
if resp and 'data' in resp:
dbData += resp['data']
# get data from internal database
session = sickrage.app.cache_db.session()
dbData += [x.as_dict() for x in
session.query(CacheDB.Provider).filter_by(provider=self.providerID,
series_id=series_id,
season=season).filter(CacheDB.Provider.episodes.contains("|{}|".format(episode)))]
for curResult in dbData:
result = self.provider.get_result()
result.series_id = int(curResult["series_id"])
result.series_provider_id = curResult["series_provider_id"]
# skip if series provider id is not set
if not curResult["series_provider_id"]:
continue
# convert to series provider id enum
if not isinstance(result.series_provider_id, SeriesProviderID):
result.series_provider_id = SeriesProviderID[curResult["series_provider_id"]]
# get series, if it's not one of our shows then ignore it
series = find_show(result.series_id, result.series_provider_id)
if not series or series.series_provider_id != series_provider_id:
continue
# ignored/required words, and non-tv junk
if not show_names.filter_bad_releases(curResult["name"]):
continue
# skip if provider is anime only and show is not anime
if self.provider.anime_only and not series.is_anime:
sickrage.app.log.debug("" + str(series.name) + " is not an anime, skiping")
continue
# get season and ep data (ignoring multi-eps for now)
curSeason = int(curResult["season"])
if curSeason == -1:
continue
result.season = curSeason
result.episodes = [int(curEp) for curEp in filter(None, curResult["episodes"].split("|"))]
result.quality = Qualities(curResult["quality"])
result.release_group = curResult["release_group"]
result.version = curResult["version"]
# make sure we want the episode
wantEp = False
for result_episode in result.episodes:
if series.want_episode(result.season, result_episode, result.quality, manualSearch, downCurQuality):
wantEp = True
if not wantEp:
sickrage.app.log.info("Skipping " + curResult["name"] + " because we don't want an episode that's " + result.quality.display_name)
continue
# build a result object
result.name = curResult["name"]
result.url = curResult["url"]
sickrage.app.log.info("Found cached {} result {}".format(result.provider_type, result.name))
result.seeders = curResult.get("seeders", -1)
result.leechers = curResult.get("leechers", -1)
result.size = curResult.get("size", -1)
result.content = None
# add it to the list
if episode not in cache_results:
cache_results[int(episode)] = [result]
else:
cache_results[int(episode)] += [result]
# datetime stamp this search so cache gets cleared
self.last_search = datetime.datetime.today()
return cache_results
================================================
FILE: sickrage/core/classes.py
================================================
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
#
# This file is part of SiCKRAGE.
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
import datetime
import sys
from collections import deque
from sickrage.core.common import dateTimeFormat
class UIError(object):
"""
Represents an error to be displayed in the web UI.
"""
def __init__(self, message):
self.time = datetime.datetime.now().strftime(dateTimeFormat)
self.title = sys.exc_info()[-2] or message
self.message = message
class UIWarning(object):
"""
Represents an error to be displayed in the web UI.
"""
def __init__(self, message):
self.time = datetime.datetime.now().strftime(dateTimeFormat)
self.title = sys.exc_info()[-2] or message
self.message = message
class ErrorViewer(object):
"""
Keeps a static list of UIErrors to be displayed on the UI and allows
the list to be cleared.
"""
def __init__(self):
self.errors = deque(maxlen=100)
def add(self, error, ui=False):
self.errors += [(error, UIError(error))[ui]]
def clear(self):
self.errors.clear()
def get(self, *args, **kwargs):
return self.errors
def count(self):
return len(self.errors)
class WarningViewer(object):
"""
Keeps a static list of (warning) UIErrors to be displayed on the UI and allows
the list to be cleared.
"""
def __init__(self):
self.warnings = deque(maxlen=100)
def add(self, warning, ui=False):
self.warnings += [(warning, UIWarning(warning))[ui]]
def clear(self):
self.warnings.clear()
def get(self, *args, **kwargs):
return self.warnings
def count(self):
return len(self.warnings)
================================================
FILE: sickrage/core/common.py
================================================
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
#
# This file is part of SiCKRAGE.
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# CPU Presets for sleep timers
import enum
import operator
import pathlib
import re
from functools import reduce
from aenum import IntEnum, extend_enum
from sickrage.core.helpers.metadata import get_file_metadata, get_resolution
countryList = {'Australia': 'AU',
'Canada': 'CA',
'USA': 'US'}
dateFormat = '%Y-%m-%d'
dateTimeFormat = '%Y-%m-%d %H:%M:%S'
timeFormat = '%A %I:%M %p'
# Other constants
MULTI_EP_RESULT = -1
SEASON_RESULT = -2
class EpisodeStatus(IntEnum):
UNKNOWN = -1 # SHOULD NEVER HAPPEN
UNAIRED = 1 # EPISODES THAT HAVEN'T AIRED YET
SNATCHED = 2 # QUALIFIED WITH QUALITY
WANTED = 3 # EPISODES WE DON'T HAVE BUT WANT TO GET
DOWNLOADED = 4 # QUALIFIED WITH QUALITY
SKIPPED = 5 # EPISODES WE DON'T WANT
ARCHIVED = 6 # EPISODES THAT YOU DON'T HAVE LOCALLY (COUNTS TOWARD DOWNLOAD COMPLETION STATS)
IGNORED = 7 # EPISODES THAT YOU DON'T WANT INCLUDED IN YOUR DOWNLOAD STATS
SNATCHED_PROPER = 9 # QUALIFIED WITH QUALITY
SUBTITLED = 10 # QUALIFIED WITH QUALITY
FAILED = 11 # EPISODE DOWNLOADED OR SNATCHED WE DON'T WANT
SNATCHED_BEST = 12 # EPISODE REDOWNLOADED USING BEST QUALITY
MISSED = 13
@classmethod
def _strings(cls):
return {
cls.UNKNOWN.name: "Unknown",
cls.UNAIRED.name: "Unaired",
cls.SNATCHED.name: "Snatched",
cls.SNATCHED_PROPER.name: "Snatched (Proper)",
cls.SNATCHED_BEST.name: "Snatched (Best)",
cls.DOWNLOADED.name: "Downloaded",
cls.SKIPPED.name: "Skipped",
cls.WANTED.name: "Wanted",
cls.ARCHIVED.name: "Archived",
cls.IGNORED.name: "Ignored",
cls.SUBTITLED.name: "Subtitled",
cls.FAILED.name: "Failed",
cls.MISSED.name: "Missed"
}
@classmethod
def _prefix_strings(cls):
return {
cls.DOWNLOADED.name: _("Downloaded"),
cls.SNATCHED.name: _("Snatched"),
cls.SNATCHED_PROPER.name: _("Snatched (Proper)"),
cls.SNATCHED_BEST.name: _("Snatched (Best)"),
cls.ARCHIVED.name: _("Archived"),
cls.FAILED.name: _("Failed"),
cls.MISSED.name: _("Missed")
}
@property
def display_name(self):
status, quality = Quality.split_composite_status(self)
if quality == Qualities.NONE:
return self._strings()[status.name]
return self._strings()[status.name] + " (" + quality.display_name + ")"
@property
def prefix_name(self):
return self._prefix_strings()[self.name]
@staticmethod
def composites(status):
return {
EpisodeStatus.DOWNLOADED: [EpisodeStatus[f"{EpisodeStatus.DOWNLOADED.name}_{q.name}"] for q in Qualities if not q.is_preset],
EpisodeStatus.SNATCHED: [EpisodeStatus[f"{EpisodeStatus.SNATCHED.name}_{q.name}"] for q in Qualities if not q.is_preset],
EpisodeStatus.SNATCHED_PROPER: [EpisodeStatus[f"{EpisodeStatus.SNATCHED_PROPER.name}_{q.name}"] for q in Qualities if not q.is_preset],
EpisodeStatus.SNATCHED_BEST: [EpisodeStatus[f"{EpisodeStatus.SNATCHED_BEST.name}_{q.name}"] for q in Qualities if not q.is_preset],
EpisodeStatus.ARCHIVED: [EpisodeStatus[f"{EpisodeStatus.ARCHIVED.name}_{q.name}"] for q in Qualities if not q.is_preset],
EpisodeStatus.FAILED: [EpisodeStatus[f"{EpisodeStatus.FAILED.name}_{q.name}"] for q in Qualities if not q.is_preset],
EpisodeStatus.IGNORED: [EpisodeStatus[f"{EpisodeStatus.IGNORED.name}_{q.name}"] for q in Qualities if not q.is_preset],
}[status]
class Overview(enum.Enum):
UNAIRED = EpisodeStatus.UNAIRED.value # 1
SNATCHED = EpisodeStatus.SNATCHED.value # 2
WANTED = EpisodeStatus.WANTED.value # 3
GOOD = EpisodeStatus.DOWNLOADED.value # 4
SKIPPED = EpisodeStatus.SKIPPED.value # 5
SNATCHED_PROPER = EpisodeStatus.SNATCHED_PROPER.value # 9
SNATCHED_BEST = EpisodeStatus.SNATCHED_BEST.value # 12
MISSED = EpisodeStatus.MISSED.value # 13
LOW_QUALITY = 50
@property
def _strings(self):
return {
self.SKIPPED.name: "skipped",
self.WANTED.name: "wanted",
self.LOW_QUALITY.name: "low-quality",
self.GOOD.name: "good",
self.UNAIRED.name: "unaired",
self.SNATCHED.name: "snatched",
self.SNATCHED_BEST.name: "snatched",
self.SNATCHED_PROPER.name: "snatched",
self.MISSED.name: "missed"
}
@property
def css_name(self):
return self._strings[self.name]
class Quality(object):
@staticmethod
def combine_qualities(anyQualities, bestQualities):
any_quality = 0
best_quality = 0
if anyQualities:
any_quality = reduce(operator.or_, anyQualities, any_quality)
if bestQualities:
best_quality = reduce(operator.or_, bestQualities, best_quality)
return any_quality | (best_quality << 16)
@staticmethod
def split_quality(quality):
any_qualities = [quality_flag for quality_flag in Qualities if
quality_flag in Qualities(quality) and quality_flag and not quality_flag.is_preset]
best_qualities = [quality_flag for quality_flag in Qualities if
quality_flag in Qualities(quality >> 16) and quality_flag and not quality_flag.is_preset]
return sorted(any_qualities), sorted(best_qualities)
@staticmethod
def name_quality(name, anime=False):
"""
Return The quality from an episode File renamed by SiCKRAGE
If no quality is achieved it will try sceneQuality regex
:param anime: Boolean to indicate if the show we're resolving is Anime
:return: Quality prefix
"""
# Try Scene names first
quality = Quality.scene_quality(name, anime)
if quality != Qualities.UNKNOWN:
return quality
quality = Quality.quality_from_file_meta(name)
if quality != Qualities.UNKNOWN:
return quality
if name.lower().endswith(".ts"):
return Qualities.RAWHDTV
return Qualities.UNKNOWN
@staticmethod
def scene_quality(name, anime=False):
"""
Return The quality from the scene episode File
:param name: Episode filename to analyse
:param anime: Boolean to indicate if the show we're resolving is Anime
:return: Quality prefix
"""
ret = Qualities.UNKNOWN
if not name:
return ret
name = pathlib.Path(name).name
check_name = lambda l, func: func([re.search(x, name, re.I) for x in l])
if anime:
dvd_options = check_name([r"dvd", r"dvdrip"], any)
blue_ray_options = check_name([r"BD", r"blue?-?ray"], any)
sd_options = check_name([r"360p", r"480p", r"848x480", r"XviD"], any)
hd_options = check_name([r"720p", r"1280x720", r"960x720"], any)
full_hd = check_name([r"1080p", r"1920x1080"], any)
if sd_options and not blue_ray_options and not dvd_options:
ret = Qualities.SDTV
elif dvd_options:
ret = Qualities.SDDVD
elif hd_options and not blue_ray_options and not full_hd:
ret = Qualities.HDTV
elif full_hd and not blue_ray_options and not hd_options:
ret = Qualities.FULLHDTV
elif hd_options and not blue_ray_options and not full_hd:
ret = Qualities.HDWEBDL
elif blue_ray_options and hd_options and not full_hd:
ret = Qualities.HDBLURAY
elif blue_ray_options and full_hd and not hd_options:
ret = Qualities.FULLHDBLURAY
return ret
if (check_name([r"480p|\bweb\b|web.?dl|web(rip|mux|hd)|[sph]d.?tv|dsr|tv(rip|mux)|satrip", r"xvid|divx|[xh].?26[45]"], all)
and not check_name([r"(720|1080|2160|4320)[pi]"], all)
and not check_name([r"hr.ws.pdtv.[xh].?26[45]"], any)):
ret = Qualities.SDTV
elif (check_name([r"dvd(rip|mux)|b[rd](rip|mux)|blue?-?ray", r"xvid|divx|[xh].?26[45]"], all)
and not check_name([r"(720|1080|2160|4320)[pi]"], all)
and not check_name([r"hr.ws.pdtv.[xh].?26[45]"], any)):
ret = Qualities.SDDVD
elif (check_name([r"720p", r"hd.?tv", r"[xh].?26[45]"], all)
or check_name([r"720p", r"hevc", r"[xh].?26[45]"], all)
or check_name([r"hr.ws.pdtv.[xh].?26[45]"], any) and not check_name([r"1080[pi]"], all)):
ret = Qualities.HDTV
elif (check_name([r"720p|1080i", r"hd.?tv", r"mpeg-?2"], all)
or check_name([r"1080[pi].hdtv", r"h.?26[45]"], all)):
ret = Qualities.RAWHDTV
elif (check_name([r"1080p", r"hd.?tv", r"[xh].?26[45]"], all)
or check_name([r"1080p", r"hevc", r"[xh].?26[45]"], all)):
ret = Qualities.FULLHDTV
elif (check_name([r"720p", r"\bweb\b|web.?dl|web(rip|mux|hd)"], all)
or check_name([r"720p", r"itunes", r"[xh].?26[45]"], all)):
ret = Qualities.HDWEBDL
elif (check_name([r"1080p", r"\bweb\b|web.?dl|web(rip|mux|hd)"], all)
or check_name([r"1080p", r"itunes", r"[xh].?26[45]"], all)):
ret = Qualities.FULLHDWEBDL
elif check_name([r"720p", r"blue?-?ray|hddvd|b[rd](rip|mux)", r"[xh].?26[45]"], all):
ret = Qualities.HDBLURAY
elif check_name([r"1080p", r"blue?-?ray|hddvd|b[rd](rip|mux)", r"[xh].?26[45]"], all):
ret = Qualities.FULLHDBLURAY
elif check_name([r"2160p", r"hd.?tv", r"[xh].?26[45]"], all):
ret = Qualities.UHD_4K_TV
elif check_name([r"4320p", r"hd.?tv", r"[xh].?26[45]"], all):
ret = Qualities.UHD_8K_TV
elif (check_name([r"2160p", r"\bweb\b|web.?dl|web(rip|mux|hd)"], all)
or check_name([r"2160p", r"itunes", r"[xh].?26[45]"], all)):
ret = Qualities.UHD_4K_WEBDL
elif (check_name([r"4320p", r"\bweb\b|web.?dl|web(rip|mux|hd)"], all)
or check_name([r"4320p", r"itunes", r"[xh].?26[45]"], all)):
ret = Qualities.UHD_8K_WEBDL
elif check_name([r"2160p", r"blue?-?ray|hddvd|b[rd](rip|mux)", r"[xh].?26[45]"], all):
ret = Qualities.UHD_4K_BLURAY
elif check_name([r"4320p", r"blue?-?ray|hddvd|b[rd](rip|mux)", r"[xh].?26[45]"], all):
ret = Qualities.UHD_8K_BLURAY
return ret
@staticmethod
def composite_status(status, quality):
return EpisodeStatus(status + 100 * quality)
@staticmethod
def split_composite_status(status):
"""Returns a tuple containing (status, quality)"""
if status == EpisodeStatus.UNKNOWN:
return status, Qualities.UNKNOWN
for q in sorted(Qualities, reverse=True):
if status > q * 100:
return EpisodeStatus(status - q * 100), q
return status, Qualities.NONE
@staticmethod
def quality_from_file_meta(filename):
"""
Get quality from file metadata
:param filename: Filename to analyse
:return: Quality prefix
"""
data = {}
quality = Qualities.UNKNOWN
try:
if pathlib.Path(filename).is_file():
meta = get_file_metadata(filename)
if meta.get('resolution_width') and meta.get('resolution_height'):
data['resolution_width'] = meta.get('resolution_width')
data['resolution_height'] = meta.get('resolution_height')
data['aspect'] = round(float(meta.get('resolution_width')) / meta.get('resolution_height', 1), 2)
else:
data.update(get_resolution(filename))
base_filename = pathlib.Path(filename).name
bluray = re.search(r"blue?-?ray|hddvd|b[rd](rip|mux)", base_filename, re.I) is not None
webdl = re.search(r"\bweb\b|web.?dl|web(rip|mux|hd)", base_filename, re.I) is not None
if 3240 < data['resolution_height']:
quality = ((Qualities.UHD_8K_TV, Qualities.UHD_8K_BLURAY)[bluray], Qualities.UHD_8K_WEBDL)[webdl]
if 1620 < data['resolution_height'] <= 3240:
quality = ((Qualities.UHD_4K_TV, Qualities.UHD_4K_BLURAY)[bluray], Qualities.UHD_4K_WEBDL)[webdl]
elif 800 < data['resolution_height'] <= 1620:
quality = ((Qualities.FULLHDTV, Qualities.FULLHDBLURAY)[bluray], Qualities.FULLHDWEBDL)[webdl]
elif 680 < data['resolution_height'] < 800:
quality = ((Qualities.HDTV, Qualities.HDBLURAY)[bluray], Qualities.HDWEBDL)[webdl]
elif data['resolution_height'] < 680:
quality = (Qualities.SDTV, Qualities.SDDVD)[re.search(r'dvd|b[rd]rip|blue?-?ray', base_filename, re.I) is not None]
except Exception:
pass
return quality
@staticmethod
def scene_quality_from_name(name, quality):
"""
Get scene naming parameters from filename and quality
:param name: Filename to check
:param quality: int of quality to make sure we get the right rip type
:return: encoder type for scene quality naming
"""
codecList = ['xvid', 'divx']
x264List = ['x264', 'x 264', 'x.264']
h264List = ['h264', 'h 264', 'h.264', 'avc']
x265List = ['x265', 'x 265', 'x.265']
h265List = ['h265', 'h 265', 'h.265', 'hevc']
codecList.extend(x264List + h264List + x265List + h265List)
found_codecs = {}
found_codec = None
rip_type = ""
for codec in codecList:
if codec in name.lower():
found_codecs[name.lower().rfind(codec)] = codec
if found_codecs:
sorted_codecs = sorted(found_codecs, reverse=True)
found_codec = found_codecs[list(sorted_codecs)[0]]
if quality == Qualities.SDDVD:
if re.search(r"b(r|d|rd)?([- .])?(rip|mux)", name.lower()):
rip_type = " BDRip"
elif re.search(r"(dvd)([- .])?(rip|mux)?", name.lower()):
rip_type = " DVDRip"
else:
rip_type = ""
if found_codec:
if codecList[0] in found_codec:
found_codec = 'XviD'
elif codecList[1] in found_codec:
found_codec = 'DivX'
elif found_codec in x264List:
found_codec = x264List[0]
elif found_codec in h264List:
found_codec = h264List[0]
elif found_codec in x265List:
found_codec = x265List[0]
elif found_codec in h265List:
found_codec = h265List[0]
if quality == Qualities.SDDVD:
return rip_type + " " + found_codec
else:
return " " + found_codec
elif quality == Qualities.SDDVD:
return rip_type
else:
return ""
@staticmethod
def status_from_name(name, assume=True, anime=False):
"""
Get a status object from filename
:param name: Filename to check
:param assume: boolean to assume quality by extension if we can't figure it out
:param anime: boolean to enable anime parsing
:return: Composite status/quality object
"""
quality = Quality.name_quality(name, anime)
return Quality.composite_status(EpisodeStatus.DOWNLOADED, quality)
@staticmethod
def from_guessit(guess):
"""
Return a Quality from a guessit dict.
:param guess: guessit dict
:type guess: dict
:return: quality
:rtype: int
"""
guessit_map = {
'720p': {
'HDTV': Qualities.HDTV,
'Web': Qualities.HDWEBDL,
'Blu-ray': Qualities.HDBLURAY,
},
'1080i': Qualities.RAWHDTV,
'1080p': {
'HDTV': Qualities.FULLHDTV,
'Web': Qualities.FULLHDWEBDL,
'Blu-ray': Qualities.FULLHDBLURAY
},
'2160p': {
'HDTV': Qualities.UHD_4K_TV,
'Web': Qualities.UHD_4K_WEBDL,
'Blu-ray': Qualities.UHD_4K_BLURAY
},
'4320p': {
'HDTV': Qualities.UHD_8K_TV,
'Web': Qualities.UHD_8K_WEBDL,
'Blu-ray': Qualities.UHD_8K_BLURAY
}
}
screen_size = guess.get('screen_size')
source = guess.get('source')
if not screen_size or isinstance(screen_size, list):
return Qualities.UNKNOWN
source_map = guessit_map.get(screen_size)
if not source_map:
return Qualities.UNKNOWN
if isinstance(source_map, int):
return source_map
if not source or isinstance(source, list):
return Qualities.UNKNOWN
quality = source_map.get(source)
return quality if quality is not None else Qualities.UNKNOWN
@staticmethod
def to_guessit(quality):
"""
Return a guessit dict containing 'screen_size and source' from a Quality.
:param quality: a quality
:type quality: int
:return: dict {'screen_size': , 'source': }
:rtype: dict (str, str)
"""
if quality not in Qualities:
quality = Qualities.UNKNOWN
screen_size = Quality.to_guessit_screen_size(quality)
source = Quality.to_guessit_source(quality)
result = {}
if screen_size:
result['screen_size'] = screen_size
if source:
result['source'] = source
return result
@staticmethod
def to_guessit_source(quality):
"""
Return a guessit source from a Quality.
:param quality: the quality
:type quality: int
:return: guessit source
:rtype: str
"""
source_map = {
Qualities.ANYHDTV | Qualities.UHD_4K_TV | Qualities.UHD_8K_TV: 'HDTV',
Qualities.ANYWEBDL | Qualities.UHD_4K_WEBDL | Qualities.UHD_8K_WEBDL: 'Web',
Qualities.ANYBLURAY | Qualities.UHD_4K_BLURAY | Qualities.UHD_8K_BLURAY: 'Blu-ray'
}
for quality_set, source in source_map.items():
if quality_set & quality:
return source
@staticmethod
def to_guessit_screen_size(quality):
"""
Return a guessit screen_size from a Quality.
:param quality: the quality
:type quality: int
:return: guessit screen_size
:rtype: str
"""
screen_size_map = {
Qualities.HDTV | Qualities.HDWEBDL | Qualities.HDBLURAY: '720p',
Qualities.RAWHDTV: '1080i',
Qualities.FULLHDTV | Qualities.FULLHDWEBDL | Qualities.FULLHDBLURAY: '1080p',
Qualities.UHD_4K_TV | Qualities.UHD_4K_WEBDL | Qualities.UHD_4K_BLURAY: '2160p',
Qualities.UHD_8K_TV | Qualities.UHD_8K_WEBDL | Qualities.UHD_8K_BLURAY: '4320p',
}
for quality_set, screen_size in screen_size_map.items():
if quality_set & quality:
return screen_size
class Qualities(enum.IntFlag):
NONE = 0 # 0
SDTV = 1 # 1
SDDVD = 1 << 1 # 2
HDTV = 1 << 2 # 4
RAWHDTV = 1 << 3 # 8 -- 720P/1080I MPEG2 (TROLLHD RELEASES)
FULLHDTV = 1 << 4 # 16 -- 1080P HDTV (QCF RELEASES)
HDWEBDL = 1 << 5 # 32
FULLHDWEBDL = 1 << 6 # 64 -- 1080P WEB-DL
HDBLURAY = 1 << 7 # 128
FULLHDBLURAY = 1 << 8 # 256
UHD_4K_TV = 1 << 9 # 512 -- 2160P AKA 4K UHD AKA UHD-1
UHD_4K_WEBDL = 1 << 10 # 1024
UHD_4K_BLURAY = 1 << 11 # 2048
UHD_8K_TV = 1 << 12 # 4096 -- 4320P AKA 8K UHD AKA UHD-2
UHD_8K_WEBDL = 1 << 13 # 8192
UHD_8K_BLURAY = 1 << 14 # 16384
ANYHDTV = HDTV | FULLHDTV # 20
ANYWEBDL = HDWEBDL | FULLHDWEBDL # 96
ANYBLURAY = HDBLURAY | FULLHDBLURAY
UNKNOWN = 1 << 15 # 32768
# Presets
SD = Quality.combine_qualities([SDTV, SDDVD], [])
HD720P = Quality.combine_qualities([HDTV, HDWEBDL, HDBLURAY], [])
HD1080P = Quality.combine_qualities([FULLHDTV, FULLHDWEBDL, FULLHDBLURAY], [])
HD = Quality.combine_qualities([HD720P, HD1080P, RAWHDTV], [])
UHD_4K = Quality.combine_qualities([UHD_4K_TV, UHD_4K_WEBDL, UHD_4K_BLURAY], [])
UHD_8K = Quality.combine_qualities([UHD_8K_TV, UHD_8K_WEBDL, UHD_8K_BLURAY], [])
UHD = Quality.combine_qualities([UHD_4K, UHD_8K], [])
ANY = Quality.combine_qualities([SD, HD, UHD], [])
ANY_PLUS_UNKNOWN = Quality.combine_qualities([UNKNOWN, SD, HD, UHD], [])
@property
def _strings(self):
return {
self.NONE.name: "N/A",
self.UNKNOWN.name: "Unknown",
self.SDTV.name: "SDTV",
self.SDDVD.name: "SD DVD",
self.HDTV.name: "720p HDTV",
self.RAWHDTV.name: "RawHD",
self.FULLHDTV.name: "1080p HDTV",
self.HDWEBDL.name: "720p WEB-DL",
self.FULLHDWEBDL.name: "1080p WEB-DL",
self.HDBLURAY.name: "720p BluRay",
self.FULLHDBLURAY.name: "1080p BluRay",
self.UHD_4K_TV.name: "4K UHD TV",
self.UHD_8K_TV.name: "8K UHD TV",
self.UHD_4K_WEBDL.name: "4K UHD WEB-DL",
self.UHD_8K_WEBDL.name: "8K UHD WEB-DL",
self.UHD_4K_BLURAY.name: "4K UHD BluRay",
self.UHD_8K_BLURAY.name: "8K UHD BluRay"
}
@property
def _preset_strings(self):
return {
self.SD.name: "SD",
self.HD.name: "HD",
self.HD720P.name: "HD720p",
self.HD1080P.name: "HD1080p",
self.UHD.name: "UHD",
self.UHD_4K.name: "UHD-4K",
self.UHD_8K.name: "UHD-8K",
self.ANY.name: "Any",
self.ANY_PLUS_UNKNOWN.name: "Any + Unknown"
}
@property
def _scene_strings(self):
return {
self.NONE.name: "N/A",
self.UNKNOWN.name: "Unknown",
self.SDTV.name: "HDTV",
self.SDDVD.name: "",
self.HDTV.name: "720p HDTV",
self.RAWHDTV.name: "1080i HDTV",
self.FULLHDTV.name: "1080p HDTV",
self.HDWEBDL.name: "720p WEB-DL",
self.FULLHDWEBDL.name: "1080p WEB-DL",
self.HDBLURAY.name: "720p BluRay",
self.FULLHDBLURAY.name: "1080p BluRay",
self.UHD_4K_TV.name: "4K UHD TV",
self.UHD_8K_TV.name: "8K UHD TV",
self.UHD_4K_WEBDL.name: "4K UHD WEB-DL",
self.UHD_8K_WEBDL.name: "8K UHD WEB-DL",
self.UHD_4K_BLURAY.name: "4K UHD BluRay",
self.UHD_8K_BLURAY.name: "8K UHD BluRay"
}
@property
def _css_strings(self):
return {
self.NONE.name: "N/A",
self.UNKNOWN.name: "Unknown",
self.SDTV.name: "SDTV",
self.SDDVD.name: "SDDVD",
self.HDTV.name: "HD720p",
self.RAWHDTV.name: "RawHD",
self.FULLHDTV.name: "HD1080p",
self.HDWEBDL.name: "HD720p",
self.FULLHDWEBDL.name: "HD1080p",
self.HDBLURAY.name: "HD720p",
self.FULLHDBLURAY.name: "HD1080p",
self.UHD_4K_TV.name: "UHD-4K",
self.UHD_8K_TV.name: "UHD-8K",
self.UHD_4K_WEBDL.name: "UHD-4K",
self.UHD_8K_WEBDL.name: "UHD-8K",
self.UHD_4K_BLURAY.name: "UHD-4K",
self.UHD_8K_BLURAY.name: "UHD-8K",
self.ANYHDTV.name: "any-hd",
self.ANYWEBDL.name: "any-hd",
self.ANYBLURAY.name: "any-hd"
}
@property
def _combined_strings(self):
return {
self.ANYHDTV.name: "HDTV",
self.ANYWEBDL.name: "WEB-DL",
self.ANYBLURAY.name: "BluRay"
}
@property
def display_name(self):
if self.name in self._strings:
return self._strings[self.name]
elif self.name in self._preset_strings:
return self._preset_strings[self.name]
elif self.name in self._combined_strings:
return self._combined_strings[self.name]
return "Custom"
@property
def scene_name(self):
if self.name in self._scene_strings:
return self._scene_strings[self.name]
return ""
@property
def css_name(self):
if self.name in self._css_strings:
return self._css_strings[self.name]
elif self.name in self._preset_strings:
return self._preset_strings[self.name]
return ""
@property
def is_preset(self):
return self.name in self._preset_strings
@property
def is_combined(self):
return self.name in self._combined_strings
# extend episode status enum class with composite statuses
[extend_enum(EpisodeStatus, f"{status.name}_{q.name}", status + 100 * q)
for status in list(EpisodeStatus).copy() for q in Qualities if not q.is_preset and status in [EpisodeStatus.DOWNLOADED,
EpisodeStatus.SNATCHED,
EpisodeStatus.SNATCHED_BEST,
EpisodeStatus.SNATCHED_PROPER,
EpisodeStatus.ARCHIVED,
EpisodeStatus.FAILED,
EpisodeStatus.IGNORED,
EpisodeStatus.SUBTITLED]]
================================================
FILE: sickrage/core/config/__init__.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import os
from sqlalchemy import orm
from sqlalchemy.orm.attributes import flag_modified
import sickrage
from sickrage.core.common import Qualities, EpisodeStatus
from sickrage.core.config.helpers import decrypt_config
from sickrage.core.databases.config import ConfigDB, CustomStringEncryptedType
from sickrage.core.databases.config.schemas import GeneralSchema, GUISchema, BlackholeSchema, SABnzbdSchema, NZBgetSchema, SynologySchema, \
TorrentSchema, KodiSchema, PlexSchema, EmbySchema, GrowlSchema, FreeMobileSchema, TelegramSchema, JoinSchema, ProwlSchema, TwitterSchema, TwilioSchema, \
Boxcar2Schema, PushoverSchema, LibnotifySchema, NMJSchema, NMJv2Schema, SlackSchema, DiscordSchema, TraktSchema, PyTivoSchema, NMASchema, PushalotSchema, \
PushbulletSchema, EmailSchema, AlexaSchema, SubtitlesSchema, FailedDownloadsSchema, FailedSnatchesSchema, QualitySizesSchema, AniDBSchema, \
MetadataProvidersSchema, SearchProvidersTorrentSchema, SearchProvidersNzbSchema, SearchProvidersTorrentRssSchema, SearchProvidersNewznabSchema
from sickrage.core.enums import UserPermission, CheckPropersInterval, NzbMethod, ProcessMethod, FileTimestampTimezone, MultiEpNaming, \
DefaultHomePage, TorrentMethod, SearchFormat, PosterSortDirection, HomeLayout, PosterSortBy, \
TimezoneDisplay, HistoryLayout, UITheme, TraktAddMethod, SeriesProviderID, CpuPreset
from sickrage.core.helpers import arg_to_bool, auto_type
from sickrage.core.helpers.encryption import load_private_key
from sickrage.core.tv.show.coming_episodes import ComingEpsLayout, ComingEpsSortBy
from sickrage.notification_providers.nmjv2 import NMJv2Location
from sickrage.search_providers import SearchProviderType, TorrentRssProvider, NewznabProvider
class Config(object):
def __init__(self, db_type, db_prefix, db_host, db_port, db_username, db_password):
self.db = ConfigDB(db_type, db_prefix, db_host, db_port, db_username, db_password)
self._config_data = {}
self.quality_sizes = {}
@property
def user(self):
return self._config_data.get(self.db.Users)
@property
def general(self):
return self._config_data.get(self.db.General)
@property
def gui(self):
return self._config_data.get(self.db.GUI)
@property
def blackhole(self):
return self._config_data.get(self.db.Blackhole)
@property
def sabnzbd(self):
return self._config_data.get(self.db.SABnzbd)
@property
def nzbget(self):
return self._config_data.get(self.db.NZBget)
@property
def synology(self):
return self._config_data.get(self.db.Synology)
@property
def torrent(self):
return self._config_data.get(self.db.Torrent)
@property
def kodi(self):
return self._config_data.get(self.db.Kodi)
@property
def plex(self):
return self._config_data.get(self.db.Plex)
@property
def emby(self):
return self._config_data.get(self.db.Emby)
@property
def growl(self):
return self._config_data.get(self.db.Growl)
@property
def freemobile(self):
return self._config_data.get(self.db.FreeMobile)
@property
def telegram(self):
return self._config_data.get(self.db.Telegram)
@property
def join_app(self):
return self._config_data.get(self.db.Join)
@property
def prowl(self):
return self._config_data.get(self.db.Prowl)
@property
def twitter(self):
return self._config_data.get(self.db.Twitter)
@property
def twilio(self):
return self._config_data.get(self.db.Twilio)
@property
def boxcar2(self):
return self._config_data.get(self.db.Boxcar2)
@property
def pushover(self):
return self._config_data.get(self.db.Pushover)
@property
def libnotify(self):
return self._config_data.get(self.db.Libnotify)
@property
def nmj(self):
return self._config_data.get(self.db.NMJ)
@property
def nmjv2(self):
return self._config_data.get(self.db.NMJv2)
@property
def slack(self):
return self._config_data.get(self.db.Slack)
@property
def discord(self):
return self._config_data.get(self.db.Discord)
@property
def trakt(self):
return self._config_data.get(self.db.Trakt)
@property
def pytivo(self):
return self._config_data.get(self.db.PyTivo)
@property
def nma(self):
return self._config_data.get(self.db.NMA)
@property
def pushalot(self):
return self._config_data.get(self.db.Pushalot)
@property
def pushbullet(self):
return self._config_data.get(self.db.Pushbullet)
@property
def email(self):
return self._config_data.get(self.db.Email)
@property
def alexa(self):
return self._config_data.get(self.db.Alexa)
@property
def subtitles(self):
return self._config_data.get(self.db.Subtitles)
@property
def failed_downloads(self):
return self._config_data.get(self.db.FailedDownloads)
@property
def failed_snatches(self):
return self._config_data.get(self.db.FailedSnatches)
@property
def anidb(self):
return self._config_data.get(self.db.AniDB)
def load(self):
# USERS SECTION
if not self.db.session().query(self.db.Users).first():
self.db.session().add(self.db.Users())
self.db.session().commit()
self._config_data[self.db.Users] = self.db.session().query(self.db.Users).first().as_attrdict()
# GENERAL SECTION
if not self.db.session().query(self.db.General).first():
self.db.session().add(self.db.General())
self.db.session().commit()
self._config_data[self.db.General] = self.db.session().query(self.db.General).first().as_attrdict()
# GUI SECTION
if not self.db.session().query(self.db.GUI).filter_by(user_id=self.user.id).one_or_none():
self.db.session().add(self.db.GUI(user_id=self.user.id))
self.db.session().commit()
self._config_data[self.db.GUI] = self.db.session().query(self.db.GUI).filter_by(user_id=self.user.id).one().as_attrdict()
# BLACKHOLE SECTION
if not self.db.session().query(self.db.Blackhole).first():
self.db.session().add(self.db.Blackhole())
self.db.session().commit()
self._config_data[self.db.Blackhole] = self.db.session().query(self.db.Blackhole).first().as_attrdict()
# SABNZBD SECTION
if not self.db.session().query(self.db.SABnzbd).first():
self.db.session().add(self.db.SABnzbd())
self.db.session().commit()
self._config_data[self.db.SABnzbd] = self.db.session().query(self.db.SABnzbd).first().as_attrdict()
# NZBGET SECTION
if not self.db.session().query(self.db.NZBget).first():
self.db.session().add(self.db.NZBget())
self.db.session().commit()
self._config_data[self.db.NZBget] = self.db.session().query(self.db.NZBget).first().as_attrdict()
# SYNOLOGY SECTION
if not self.db.session().query(self.db.Synology).first():
self.db.session().add(self.db.Synology())
self.db.session().commit()
self._config_data[self.db.Synology] = self.db.session().query(self.db.Synology).first().as_attrdict()
# TORRENT SECTION
if not self.db.session().query(self.db.Torrent).first():
self.db.session().add(self.db.Torrent())
self.db.session().commit()
self._config_data[self.db.Torrent] = self.db.session().query(self.db.Torrent).first().as_attrdict()
# KODI SECTION
if not self.db.session().query(self.db.Kodi).first():
self.db.session().add(self.db.Kodi())
self.db.session().commit()
self._config_data[self.db.Kodi] = self.db.session().query(self.db.Kodi).first().as_attrdict()
if not self.db.session().query(self.db.Plex).first():
self.db.session().add(self.db.Plex())
self.db.session().commit()
self._config_data[self.db.Plex] = self.db.session().query(self.db.Plex).first().as_attrdict()
if not self.db.session().query(self.db.Emby).first():
self.db.session().add(self.db.Emby())
self.db.session().commit()
self._config_data[self.db.Emby] = self.db.session().query(self.db.Emby).first().as_attrdict()
if not self.db.session().query(self.db.Growl).first():
self.db.session().add(self.db.Growl())
self.db.session().commit()
self._config_data[self.db.Growl] = self.db.session().query(self.db.Growl).first().as_attrdict()
if not self.db.session().query(self.db.FreeMobile).first():
self.db.session().add(self.db.FreeMobile())
self.db.session().commit()
self._config_data[self.db.FreeMobile] = self.db.session().query(self.db.FreeMobile).first().as_attrdict()
if not self.db.session().query(self.db.Telegram).first():
self.db.session().add(self.db.Telegram())
self.db.session().commit()
self._config_data[self.db.Telegram] = self.db.session().query(self.db.Telegram).first().as_attrdict()
if not self.db.session().query(self.db.Join).first():
self.db.session().add(self.db.Join())
self.db.session().commit()
self._config_data[self.db.Join] = self.db.session().query(self.db.Join).first().as_attrdict()
if not self.db.session().query(self.db.Prowl).first():
self.db.session().add(self.db.Prowl())
self.db.session().commit()
self._config_data[self.db.Prowl] = self.db.session().query(self.db.Prowl).first().as_attrdict()
if not self.db.session().query(self.db.Twitter).first():
self.db.session().add(self.db.Twitter())
self.db.session().commit()
self._config_data[self.db.Twitter] = self.db.session().query(self.db.Twitter).first().as_attrdict()
if not self.db.session().query(self.db.Twilio).first():
self.db.session().add(self.db.Twilio())
self.db.session().commit()
self._config_data[self.db.Twilio] = self.db.session().query(self.db.Twilio).first().as_attrdict()
if not self.db.session().query(self.db.Boxcar2).first():
self.db.session().add(self.db.Boxcar2())
self.db.session().commit()
self._config_data[self.db.Boxcar2] = self.db.session().query(self.db.Boxcar2).first().as_attrdict()
if not self.db.session().query(self.db.Pushover).first():
self.db.session().add(self.db.Pushover())
self.db.session().commit()
self._config_data[self.db.Pushover] = self.db.session().query(self.db.Pushover).first().as_attrdict()
if not self.db.session().query(self.db.Libnotify).first():
self.db.session().add(self.db.Libnotify())
self.db.session().commit()
self._config_data[self.db.Libnotify] = self.db.session().query(self.db.Libnotify).first().as_attrdict()
if not self.db.session().query(self.db.NMJ).first():
self.db.session().add(self.db.NMJ())
self.db.session().commit()
self._config_data[self.db.NMJ] = self.db.session().query(self.db.NMJ).first().as_attrdict()
if not self.db.session().query(self.db.NMJv2).first():
self.db.session().add(self.db.NMJv2())
self.db.session().commit()
self._config_data[self.db.NMJv2] = self.db.session().query(self.db.NMJv2).first().as_attrdict()
if not self.db.session().query(self.db.Slack).first():
self.db.session().add(self.db.Slack())
self.db.session().commit()
self._config_data[self.db.Slack] = self.db.session().query(self.db.Slack).first().as_attrdict()
if not self.db.session().query(self.db.Discord).first():
self.db.session().add(self.db.Discord())
self.db.session().commit()
self._config_data[self.db.Discord] = self.db.session().query(self.db.Discord).first().as_attrdict()
if not self.db.session().query(self.db.Trakt).first():
self.db.session().add(self.db.Trakt())
self.db.session().commit()
self._config_data[self.db.Trakt] = self.db.session().query(self.db.Trakt).first().as_attrdict()
if not self.db.session().query(self.db.PyTivo).first():
self.db.session().add(self.db.PyTivo())
self.db.session().commit()
self._config_data[self.db.PyTivo] = self.db.session().query(self.db.PyTivo).first().as_attrdict()
if not self.db.session().query(self.db.NMA).first():
self.db.session().add(self.db.NMA())
self.db.session().commit()
self._config_data[self.db.NMA] = self.db.session().query(self.db.NMA).first().as_attrdict()
if not self.db.session().query(self.db.Pushalot).first():
self.db.session().add(self.db.Pushalot())
self.db.session().commit()
self._config_data[self.db.Pushalot] = self.db.session().query(self.db.Pushalot).first().as_attrdict()
if not self.db.session().query(self.db.Pushbullet).first():
self.db.session().add(self.db.Pushbullet())
self.db.session().commit()
self._config_data[self.db.Pushbullet] = self.db.session().query(self.db.Pushbullet).first().as_attrdict()
if not self.db.session().query(self.db.Email).first():
self.db.session().add(self.db.Email())
self.db.session().commit()
self._config_data[self.db.Email] = self.db.session().query(self.db.Email).first().as_attrdict()
if not self.db.session().query(self.db.Alexa).first():
self.db.session().add(self.db.Alexa())
self.db.session().commit()
self._config_data[self.db.Alexa] = self.db.session().query(self.db.Alexa).first().as_attrdict()
if not self.db.session().query(self.db.Subtitles).first():
self.db.session().add(self.db.Subtitles())
self.db.session().commit()
self._config_data[self.db.Subtitles] = self.db.session().query(self.db.Subtitles).first().as_attrdict()
if not self.db.session().query(self.db.FailedDownloads).first():
self.db.session().add(self.db.FailedDownloads())
self.db.session().commit()
self._config_data[self.db.FailedDownloads] = self.db.session().query(self.db.FailedDownloads).first().as_attrdict()
if not self.db.session().query(self.db.FailedSnatches).first():
self.db.session().add(self.db.FailedSnatches())
self.db.session().commit()
self._config_data[self.db.FailedSnatches] = self.db.session().query(self.db.FailedSnatches).first().as_attrdict()
if not self.db.session().query(self.db.AniDB).first():
self.db.session().add(self.db.AniDB())
self.db.session().commit()
self._config_data[self.db.AniDB] = self.db.session().query(self.db.AniDB).first().as_attrdict()
# QUALITY SIZES
for quality in Qualities:
if quality.is_preset or quality.is_combined:
continue
if quality in [Qualities.NONE, Qualities.UNKNOWN]:
continue
if not self.db.session().query(self.db.QualitySizes).filter_by(quality=quality).one_or_none():
self.db.session().add(self.db.QualitySizes(quality=quality, min_size=0, max_size=0))
self.db.session().commit()
db_item = self.db.session().query(self.db.QualitySizes).filter_by(quality=quality).one()
self.quality_sizes[quality.name] = db_item.as_attrdict()
# CUSTOM SEARCH PROVIDERS
for search_providers in self.db.session().query(self.db.SearchProvidersTorrentRss, self.db.SearchProvidersNewznab):
for search_provider in search_providers:
if search_provider.provider_id in sickrage.app.search_providers.all():
continue
if search_provider.provider_type == SearchProviderType.TORRENT_RSS:
sickrage.app.search_providers[search_provider.provider_type.name][search_provider.provider_id] = TorrentRssProvider(**{
'name': search_provider.name,
'url': search_provider.url,
'titleTAG': search_provider.title_tag
})
elif search_provider.provider_type == SearchProviderType.NEWZNAB:
sickrage.app.search_providers[search_provider.provider_type.name][search_provider.provider_id] = NewznabProvider(**{
'name': search_provider.name,
'url': search_provider.url,
'api_key': search_provider.api_key,
'catIDs': search_provider.cat_ids
})
# SEARCH PROVIDERS
for search_provider_id, _search_provider in sickrage.app.search_providers.all().items():
search_provider = None
try:
if _search_provider.provider_type == SearchProviderType.TORRENT:
search_provider = self.db.session().query(self.db.SearchProvidersTorrent).filter_by(provider_id=search_provider_id).one()
elif _search_provider.provider_type == SearchProviderType.NZB:
search_provider = self.db.session().query(self.db.SearchProvidersNzb).filter_by(provider_id=search_provider_id).one()
elif _search_provider.provider_type == SearchProviderType.TORRENT_RSS:
search_provider = self.db.session().query(self.db.SearchProvidersTorrentRss).filter_by(provider_id=search_provider_id).one()
elif _search_provider.provider_type == SearchProviderType.NEWZNAB:
search_provider = self.db.session().query(self.db.SearchProvidersNewznab).filter_by(provider_id=search_provider_id).one()
if search_provider:
if search_provider.provider_type in [SearchProviderType.TORRENT, SearchProviderType.TORRENT_RSS]:
sickrage.app.search_providers.all()[search_provider.provider_id].ratio = search_provider.ratio
elif search_provider.provider_type in [SearchProviderType.NZB, SearchProviderType.NEWZNAB]:
sickrage.app.search_providers.all()[search_provider.provider_id].username = search_provider.username
sickrage.app.search_providers.all()[search_provider.provider_id].api_key = search_provider.api_key
sickrage.app.search_providers.all()[search_provider.provider_id].search_mode = search_provider.search_mode
sickrage.app.search_providers.all()[search_provider.provider_id].search_separator = search_provider.search_separator
sickrage.app.search_providers.all()[search_provider.provider_id].cookies = search_provider.cookies
sickrage.app.search_providers.all()[search_provider.provider_id].proper_strings = search_provider.proper_strings.split(',')
sickrage.app.search_providers.all()[search_provider.provider_id].private = search_provider.private
sickrage.app.search_providers.all()[search_provider.provider_id].supports_backlog = search_provider.supports_backlog
sickrage.app.search_providers.all()[search_provider.provider_id].supports_absolute_numbering = search_provider.supports_absolute_numbering
sickrage.app.search_providers.all()[search_provider.provider_id].anime_only = search_provider.anime_only
sickrage.app.search_providers.all()[search_provider.provider_id].search_fallback = search_provider.search_fallback
sickrage.app.search_providers.all()[search_provider.provider_id].enable_daily = search_provider.enable_daily
sickrage.app.search_providers.all()[search_provider.provider_id].enable_backlog = search_provider.enable_backlog
sickrage.app.search_providers.all()[search_provider.provider_id].enable_cookies = search_provider.enable_cookies
sickrage.app.search_providers.all()[search_provider.provider_id].enabled = search_provider.enable
sickrage.app.search_providers.all()[search_provider.provider_id].sort_order = search_provider.sort_order
sickrage.app.search_providers.all()[search_provider.provider_id].custom_settings = search_provider.custom_settings
except orm.exc.NoResultFound:
pass
# METADATA PROVIDERS
for metadata_provider_id in sickrage.app.metadata_providers:
try:
metadata_provider = self.db.session().query(self.db.MetadataProviders).filter_by(provider_id=metadata_provider_id).one()
sickrage.app.metadata_providers[metadata_provider.provider_id].show_metadata = metadata_provider.show_metadata
sickrage.app.metadata_providers[metadata_provider.provider_id].episode_metadata = metadata_provider.episode_metadata
sickrage.app.metadata_providers[metadata_provider.provider_id].fanart = metadata_provider.fanart
sickrage.app.metadata_providers[metadata_provider.provider_id].poster = metadata_provider.poster
sickrage.app.metadata_providers[metadata_provider.provider_id].banner = metadata_provider.banner
sickrage.app.metadata_providers[metadata_provider.provider_id].episode_thumbnails = metadata_provider.episode_thumbnails
sickrage.app.metadata_providers[metadata_provider.provider_id].season_posters = metadata_provider.season_posters
sickrage.app.metadata_providers[metadata_provider.provider_id].season_banners = metadata_provider.season_banners
sickrage.app.metadata_providers[metadata_provider.provider_id].season_all_poster = metadata_provider.season_all_poster
sickrage.app.metadata_providers[metadata_provider.provider_id].season_all_banner = metadata_provider.season_all_banner
sickrage.app.metadata_providers[metadata_provider.provider_id].enabled = metadata_provider.enable
except orm.exc.NoResultFound:
pass
def save(self, mark_dirty=False):
try:
# CONFIG SETTINGS
for table_name, table_data in self._config_data.items():
db_item = self.db.session().query(table_name).one()
db_item.update(**table_data)
if mark_dirty:
for column_name in table_data:
flag_modified(db_item, column_name)
self.db.session().commit()
# QUALITY SIZES
for quality_size_name, quality_size_data in self.quality_sizes.items():
db_item = self.db.session().query(self.db.QualitySizes).filter_by(quality=Qualities[quality_size_name].value).one()
db_item.update(**quality_size_data)
if mark_dirty:
for column_name in quality_size_data:
flag_modified(db_item, column_name)
self.db.session().commit()
# SEARCH PROVIDERS
for _search_provider_id, _search_provider in sickrage.app.search_providers.all().copy().items():
search_provider = None
if _search_provider.provider_type == SearchProviderType.TORRENT:
try:
search_provider = self.db.session().query(self.db.SearchProvidersTorrent).filter_by(provider_id=_search_provider_id).one()
except orm.exc.NoResultFound:
self.db.session().add(self.db.SearchProvidersTorrent(provider_id=_search_provider_id, provider_type=_search_provider.provider_type))
self.db.session().commit()
search_provider = self.db.session().query(self.db.SearchProvidersTorrent).filter_by(provider_id=_search_provider_id).one()
elif _search_provider.provider_type == SearchProviderType.NZB:
try:
search_provider = self.db.session().query(self.db.SearchProvidersNzb).filter_by(provider_id=_search_provider_id).one()
except orm.exc.NoResultFound:
self.db.session().add(self.db.SearchProvidersNzb(provider_id=_search_provider_id, provider_type=_search_provider.provider_type))
self.db.session().commit()
search_provider = self.db.session().query(self.db.SearchProvidersNzb).filter_by(provider_id=_search_provider_id).one()
elif _search_provider.provider_type == SearchProviderType.TORRENT_RSS:
try:
search_provider = self.db.session().query(self.db.SearchProvidersTorrentRss).filter_by(provider_id=_search_provider_id).one()
if _search_provider.provider_deleted:
del sickrage.app.search_providers[_search_provider.provider_type.name][_search_provider_id]
self.db.session().query(self.db.SearchProvidersTorrentRss).filter_by(provider_id=_search_provider_id).delete()
self.db.session().commit()
continue
except orm.exc.NoResultFound:
self.db.session().add(self.db.SearchProvidersTorrentRss(provider_id=_search_provider_id, provider_type=_search_provider.provider_type))
self.db.session().commit()
search_provider = self.db.session().query(self.db.SearchProvidersTorrentRss).filter_by(provider_id=_search_provider_id).one()
search_provider.name = sickrage.app.search_providers.all()[search_provider.provider_id].name
search_provider.url = sickrage.app.search_providers.all()[search_provider.provider_id].url
search_provider.title_tag = sickrage.app.search_providers.all()[search_provider.provider_id].titleTAG
elif _search_provider.provider_type == SearchProviderType.NEWZNAB:
try:
search_provider = self.db.session().query(self.db.SearchProvidersNewznab).filter_by(provider_id=_search_provider_id).one()
if _search_provider.provider_deleted:
del sickrage.app.search_providers[_search_provider.provider_type.name][_search_provider_id]
self.db.session().query(self.db.SearchProvidersNewznab).filter_by(provider_id=_search_provider_id).delete()
self.db.session().commit()
continue
except orm.exc.NoResultFound:
self.db.session().add(self.db.SearchProvidersNewznab(provider_id=_search_provider_id, provider_type=_search_provider.provider_type))
self.db.session().commit()
search_provider = self.db.session().query(self.db.SearchProvidersNewznab).filter_by(provider_id=_search_provider_id).one()
search_provider.name = sickrage.app.search_providers.all()[search_provider.provider_id].name
search_provider.url = sickrage.app.search_providers.all()[search_provider.provider_id].url
search_provider.api_key = sickrage.app.search_providers.all()[search_provider.provider_id].api_key
search_provider.cat_ids = sickrage.app.search_providers.all()[search_provider.provider_id].catIDs
if search_provider:
if search_provider.provider_type in [SearchProviderType.TORRENT, SearchProviderType.TORRENT_RSS]:
search_provider.ratio = sickrage.app.search_providers.all()[search_provider.provider_id].ratio
elif search_provider.provider_type in [SearchProviderType.NZB, SearchProviderType.NEWZNAB]:
search_provider.username = sickrage.app.search_providers.all()[search_provider.provider_id].username
search_provider.search_mode = sickrage.app.search_providers.all()[search_provider.provider_id].search_mode
search_provider.search_separator = sickrage.app.search_providers.all()[search_provider.provider_id].search_separator
search_provider.cookies = sickrage.app.search_providers.all()[search_provider.provider_id].cookies
search_provider.proper_strings = ','.join(sickrage.app.search_providers.all()[search_provider.provider_id].proper_strings)
search_provider.private = sickrage.app.search_providers.all()[search_provider.provider_id].private
search_provider.supports_backlog = sickrage.app.search_providers.all()[search_provider.provider_id].supports_backlog
search_provider.supports_absolute_numbering = sickrage.app.search_providers.all()[search_provider.provider_id].supports_absolute_numbering
search_provider.anime_only = sickrage.app.search_providers.all()[search_provider.provider_id].anime_only
search_provider.search_fallback = sickrage.app.search_providers.all()[search_provider.provider_id].search_fallback
search_provider.enable_daily = sickrage.app.search_providers.all()[search_provider.provider_id].enable_daily
search_provider.enable_backlog = sickrage.app.search_providers.all()[search_provider.provider_id].enable_backlog
search_provider.enable_cookies = sickrage.app.search_providers.all()[search_provider.provider_id].enable_cookies
search_provider.enable = sickrage.app.search_providers.all()[search_provider.provider_id].enabled
search_provider.sort_order = sickrage.app.search_providers.all()[search_provider.provider_id].sort_order
search_provider.custom_settings = sickrage.app.search_providers.all()[search_provider.provider_id].custom_settings
if mark_dirty:
for column_name in search_provider.as_dict():
flag_modified(search_provider, column_name)
self.db.session().commit()
# METADATA PROVIDERS
for metadata_provider_id in sickrage.app.metadata_providers:
try:
metadata_provider = self.db.session().query(self.db.MetadataProviders).filter_by(provider_id=metadata_provider_id).one()
except orm.exc.NoResultFound:
self.db.session().add(self.db.MetadataProviders(provider_id=metadata_provider_id))
self.db.session().commit()
metadata_provider = self.db.session().query(self.db.MetadataProviders).filter_by(provider_id=metadata_provider_id).one()
metadata_provider.show_metadata = sickrage.app.metadata_providers[metadata_provider.provider_id].show_metadata
metadata_provider.episode_metadata = sickrage.app.metadata_providers[metadata_provider.provider_id].episode_metadata
metadata_provider.fanart = sickrage.app.metadata_providers[metadata_provider.provider_id].fanart
metadata_provider.poster = sickrage.app.metadata_providers[metadata_provider.provider_id].poster
metadata_provider.banner = sickrage.app.metadata_providers[metadata_provider.provider_id].banner
metadata_provider.episode_thumbnails = sickrage.app.metadata_providers[metadata_provider.provider_id].episode_thumbnails
metadata_provider.season_posters = sickrage.app.metadata_providers[metadata_provider.provider_id].season_posters
metadata_provider.season_banners = sickrage.app.metadata_providers[metadata_provider.provider_id].season_banners
metadata_provider.season_all_poster = sickrage.app.metadata_providers[metadata_provider.provider_id].season_all_poster
metadata_provider.season_all_banner = sickrage.app.metadata_providers[metadata_provider.provider_id].season_all_banner
metadata_provider.enable = sickrage.app.metadata_providers[metadata_provider.provider_id].enabled
if mark_dirty:
for column_name in metadata_provider.as_dict():
flag_modified(metadata_provider, column_name)
self.db.session().commit()
sickrage.app.log.info("Config saved to database successfully!")
except Exception as e:
sickrage.app.log.warning("Failed to save config to database")
sickrage.app.log.debug(f"Failed to save config to database: {e}")
def reset_encryption(self):
CustomStringEncryptedType.reset = True
self.save(mark_dirty=True)
CustomStringEncryptedType.reset = False
def migrate_config_file(self, filename):
# no config.ini is present to migrate
if not os.path.exists(filename):
sickrage.app.log.debug(f'{filename} does not exist, skipping config.ini migration')
return
# config.ini has already been migrated
if os.path.exists(f'{filename}.migrated'):
sickrage.app.log.debug(f'{filename} has already been migrated, skipping config.ini migration')
return
try:
private_key_filename = os.path.join(sickrage.app.data_dir, 'privatekey.pem')
config_object = decrypt_config(filename, load_private_key(private_key_filename))
except Exception as e:
sickrage.app.log.warning(f"Unable to decrypt config file {filename}, config can not be migrated to database")
return
sickrage.app.log.info("Migrating config file to database")
# USER SETTINGS
self.user.username = self._get_config_file_value(config_object, 'General', 'web_username', default=self.user.username, field_type=str)
self.user.password = self._get_config_file_value(config_object, 'General', 'web_password', default=self.user.password, field_type=str)
self.user.sub_id = self._get_config_file_value(config_object, 'General', 'sub_id', default=self.user.sub_id, field_type=str)
self.user.permissions = UserPermission.SUPERUSER
# GENERAL SETTINGS
self.general.server_id = self._get_config_file_value(config_object, 'General', 'server_id', default=self.general.server_id, field_type=str)
self.general.sso_auth_enabled = self._get_config_file_value(config_object, 'General', 'sso_auth_enabled', default=self.general.sso_auth_enabled,
field_type=bool)
self.general.local_auth_enabled = self._get_config_file_value(config_object, 'General', 'local_auth_enabled', default=self.general.local_auth_enabled,
field_type=bool)
self.general.ip_whitelist_enabled = self._get_config_file_value(config_object, 'General', 'ip_whitelist_enabled',
default=self.general.ip_whitelist_enabled,
field_type=bool)
self.general.ip_whitelist_localhost_enabled = self._get_config_file_value(config_object, 'General', 'ip_whitelist_localhost_enabled',
default=self.general.ip_whitelist_localhost_enabled, field_type=bool)
self.general.ip_whitelist = self._get_config_file_value(config_object, 'General', 'ip_whitelist', default=self.general.ip_whitelist, field_type=str)
if not any([self.general.sso_auth_enabled, self.general.local_auth_enabled]):
self.general.sso_auth_enabled = True
self.general.enable_sickrage_api = self._get_config_file_value(config_object, 'General', 'enable_sickrage_api',
default=self.general.enable_sickrage_api,
field_type=bool)
self.general.debug = self._get_config_file_value(config_object, 'General', 'debug', default=self.general.debug,
field_type=bool)
self.general.log_nr = self._get_config_file_value(config_object, 'General', 'log_nr', default=self.general.log_nr,
field_type=int)
self.general.log_size = self._get_config_file_value(config_object, 'General', 'log_size', default=self.general.log_size,
field_type=int)
self.general.socket_timeout = self._get_config_file_value(config_object, 'General', 'socket_timeout', default=self.general.socket_timeout,
field_type=int)
self.general.default_page = DefaultHomePage[self._get_config_file_value(config_object, 'General', 'default_page', default=DefaultHomePage.HOME.name,
field_type=str.upper)]
self.general.pip3_path = self._get_config_file_value(config_object, 'General', 'pip3_path', default=self.general.pip3_path, field_type=str)
self.general.git_path = self._get_config_file_value(config_object, 'General', 'git_path', default=self.general.git_path,
field_type=str)
self.general.git_reset = self._get_config_file_value(config_object, 'General', 'git_reset', default=self.general.git_reset, field_type=bool)
self.general.web_port = self._get_config_file_value(config_object, 'General', 'web_port', default=self.general.web_port, field_type=int)
self.general.web_log = self._get_config_file_value(config_object, 'General', 'web_log', default=self.general.web_log, field_type=str)
self.general.web_external_port = self._get_config_file_value(config_object, 'General', 'web_external_port', default=self.general.web_external_port,
field_type=int)
self.general.web_ipv6 = self._get_config_file_value(config_object, 'General', 'web_ipv6', default=self.general.web_ipv6, field_type=bool)
self.general.web_root = self._get_config_file_value(config_object, 'General', 'web_root', default=self.general.web_root, field_type=str).lstrip(
'/').rstrip('/')
self.general.web_cookie_secret = self._get_config_file_value(config_object, 'General', 'web_cookie_secret', default=self.general.web_cookie_secret,
field_type=str)
self.general.web_use_gzip = self._get_config_file_value(config_object, 'General', 'web_use_gzip', default=self.general.web_use_gzip, field_type=bool)
self.general.ssl_verify = self._get_config_file_value(config_object, 'General', 'ssl_verify', default=self.general.ssl_verify, field_type=bool)
self.general.launch_browser = self._get_config_file_value(config_object, 'General', 'launch_browser', default=self.general.launch_browser,
field_type=bool)
self.general.series_provider_default_language = self._get_config_file_value(config_object, 'General', 'indexer_default_lang',
default=self.general.series_provider_default_language, field_type=str)
self.general.ep_default_deleted_status = EpisodeStatus(
self._get_config_file_value(config_object, 'General', 'ep_default_deleted_status', default=EpisodeStatus.WANTED.value, field_type=int))
self.general.download_url = self._get_config_file_value(config_object, 'General', 'download_url', default=self.general.download_url, field_type=str)
self.general.cpu_preset = CpuPreset[
self._get_config_file_value(config_object, 'General', 'cpu_preset', default=CpuPreset.NORMAL.name, field_type=str.upper)]
self.general.max_queue_workers = self._get_config_file_value(config_object, 'General', 'max_queue_workers', default=self.general.max_queue_workers,
field_type=int)
self.general.anon_redirect = self._get_config_file_value(config_object, 'General', 'anon_redirect', default=self.general.anon_redirect, field_type=str)
self.general.proxy_setting = self._get_config_file_value(config_object, 'General', 'proxy_setting', default=self.general.proxy_setting, field_type=str)
self.general.proxy_series_providers = self._get_config_file_value(config_object, 'General', 'proxy_indexers',
default=self.general.proxy_series_providers, field_type=bool)
self.general.trash_remove_show = self._get_config_file_value(config_object, 'General', 'trash_remove_show', default=self.general.trash_remove_show,
field_type=bool)
self.general.trash_rotate_logs = self._get_config_file_value(config_object, 'General', 'trash_rotate_logs', default=self.general.trash_rotate_logs,
field_type=bool)
self.general.sort_article = self._get_config_file_value(config_object, 'General', 'sort_article', default=self.general.sort_article, field_type=bool)
self.general.api_v1_key = self._get_config_file_value(config_object, 'General', 'api_key', default=self.general.api_v1_key, field_type=str)
self.general.enable_https = self._get_config_file_value(config_object, 'General', 'enable_https', default=self.general.enable_https, field_type=bool)
self.general.https_cert = self._get_config_file_value(config_object, 'General', 'https_cert', default=self.general.https_cert, field_type=str)
self.general.https_key = self._get_config_file_value(config_object, 'General', 'https_key', default=self.general.https_key, field_type=str)
self.general.handle_reverse_proxy = self._get_config_file_value(config_object, 'General', 'handle_reverse_proxy',
default=self.general.handle_reverse_proxy, field_type=bool)
self.general.root_dirs = self._get_config_file_value(config_object, 'General', 'root_dirs', default=self.general.root_dirs, field_type=str)
self.general.quality_default = Qualities(
self._get_config_file_value(config_object, 'General', 'quality_default', default=self.general.quality_default, field_type=int))
self.general.status_default = EpisodeStatus(
self._get_config_file_value(config_object, 'General', 'status_default', default=EpisodeStatus.SKIPPED.value, field_type=int))
self.general.status_default_after = EpisodeStatus(
self._get_config_file_value(config_object, 'General', 'status_default_after', default=EpisodeStatus.WANTED.value, field_type=int))
self.general.enable_upnp = self._get_config_file_value(config_object, 'General', 'enable_upnp', default=self.general.enable_upnp, field_type=bool)
self.general.version_notify = self._get_config_file_value(config_object, 'General', 'version_notify', default=self.general.version_notify,
field_type=bool)
self.general.auto_update = self._get_config_file_value(config_object, 'General', 'auto_update', default=self.general.auto_update, field_type=bool)
self.general.notify_on_update = self._get_config_file_value(config_object, 'General', 'notify_on_update', default=self.general.notify_on_update,
field_type=bool)
self.general.backup_on_update = self._get_config_file_value(config_object, 'General', 'backup_on_update', default=self.general.backup_on_update,
field_type=bool)
self.general.notify_on_login = self._get_config_file_value(config_object, 'General', 'notify_on_login', default=self.general.notify_on_login,
field_type=bool)
self.general.flatten_folders_default = self._get_config_file_value(config_object, 'General', 'flatten_folders_default',
default=self.general.flatten_folders_default, field_type=bool)
self.general.series_provider_default = SeriesProviderID.THETVDB
self.general.series_provider_timeout = self._get_config_file_value(config_object, 'General', 'indexer_timeout',
default=self.general.series_provider_timeout, field_type=int)
self.general.anime_default = self._get_config_file_value(config_object, 'General', 'anime_default', default=self.general.anime_default, field_type=bool)
self.general.search_format_default = SearchFormat(
self._get_config_file_value(config_object, 'General', 'search_format_default', default=SearchFormat.STANDARD.value, field_type=int))
self.general.scene_default = self._get_config_file_value(config_object, 'General', 'scene_default', default=self.general.scene_default, field_type=bool)
self.general.skip_downloaded_default = self._get_config_file_value(config_object, 'General', 'skip_downloaded_default',
default=self.general.skip_downloaded_default, field_type=bool)
self.general.add_show_year_default = self._get_config_file_value(config_object, 'General', 'add_show_year_default',
default=self.general.add_show_year_default, field_type=bool)
self.general.naming_pattern = self._get_config_file_value(config_object, 'General', 'naming_pattern', default=self.general.naming_pattern,
field_type=str)
self.general.naming_abd_pattern = self._get_config_file_value(config_object, 'General', 'naming_abd_pattern', default=self.general.naming_abd_pattern,
field_type=str)
self.general.naming_custom_abd = self._get_config_file_value(config_object, 'General', 'naming_custom_abd', default=self.general.naming_custom_abd,
field_type=bool)
self.general.naming_sports_pattern = self._get_config_file_value(config_object, 'General', 'naming_sports_pattern',
default=self.general.naming_sports_pattern, field_type=str)
self.general.naming_anime_pattern = self._get_config_file_value(config_object, 'General', 'naming_anime_pattern',
default=self.general.naming_anime_pattern, field_type=str)
self.general.naming_anime = self._get_config_file_value(config_object, 'General', 'naming_anime', default=self.general.naming_anime, field_type=int)
self.general.naming_custom_sports = self._get_config_file_value(config_object, 'General', 'naming_custom_sports',
default=self.general.naming_custom_sports, field_type=bool)
self.general.naming_custom_anime = self._get_config_file_value(config_object, 'General', 'naming_custom_anime',
default=self.general.naming_custom_anime, field_type=bool)
self.general.naming_multi_ep = MultiEpNaming(
self._get_config_file_value(config_object, 'General', 'naming_multi_ep', default=MultiEpNaming.REPEAT.value, field_type=int))
self.general.naming_anime_multi_ep = MultiEpNaming(
self._get_config_file_value(config_object, 'General', 'naming_anime_multi_ep', default=MultiEpNaming.REPEAT.value, field_type=int))
self.general.naming_strip_year = self._get_config_file_value(config_object, 'General', 'naming_strip_year', default=self.general.naming_strip_year,
field_type=bool)
self.general.use_nzbs = self._get_config_file_value(config_object, 'General', 'use_nzbs', default=self.general.use_nzbs, field_type=bool)
self.general.use_torrents = self._get_config_file_value(config_object, 'General', 'use_torrents', default=self.general.use_torrents, field_type=bool)
self.general.nzb_method = NzbMethod[
self._get_config_file_value(config_object, 'General', 'nzb_method', default=NzbMethod.BLACKHOLE.name, field_type=str.upper)]
self.general.torrent_method = TorrentMethod[
self._get_config_file_value(config_object, 'General', 'torrent_method', default=TorrentMethod.BLACKHOLE.name, field_type=str.upper)]
self.general.download_propers = self._get_config_file_value(config_object, 'General', 'download_propers', default=self.general.download_propers,
field_type=bool)
self.general.enable_rss_cache = self._get_config_file_value(config_object, 'General', 'enable_rss_cache', default=self.general.enable_rss_cache,
field_type=bool)
self.general.torrent_file_to_magnet = self._get_config_file_value(config_object, 'General', 'torrent_file_to_magnet',
default=self.general.torrent_file_to_magnet, field_type=bool)
self.general.torrent_magnet_to_file = self._get_config_file_value(config_object, 'General', 'torrent_magnet_to_file',
default=self.general.torrent_magnet_to_file, field_type=bool)
self.general.download_unverified_magnet_link = self._get_config_file_value(config_object, 'General', 'download_unverified_magnet_link',
field_type=bool)
self.general.proper_searcher_interval = CheckPropersInterval.DAILY
self.general.randomize_providers = self._get_config_file_value(config_object, 'General', 'randomize_providers',
default=self.general.randomize_providers, field_type=bool)
self.general.allow_high_priority = self._get_config_file_value(config_object, 'General', 'allow_high_priority',
default=self.general.allow_high_priority, field_type=bool)
self.general.skip_removed_files = self._get_config_file_value(config_object, 'General', 'skip_removed_files', default=self.general.skip_removed_files,
field_type=bool)
self.general.usenet_retention = self._get_config_file_value(config_object, 'General', 'usenet_retention', default=self.general.usenet_retention,
field_type=int)
self.general.daily_searcher_freq = self._get_config_file_value(config_object, 'General', 'dailysearch_frequency',
default=self.general.daily_searcher_freq, field_type=int)
self.general.backlog_searcher_freq = self._get_config_file_value(config_object, 'General', 'backlog_frequency',
default=self.general.backlog_searcher_freq, field_type=int)
self.general.version_updater_freq = self._get_config_file_value(config_object, 'General', 'update_frequency', default=self.general.version_updater_freq,
field_type=int)
self.general.subtitle_searcher_freq = self._get_config_file_value(config_object, 'Subtitles', 'subtitles_finder_frequency',
default=self.general.subtitle_searcher_freq, field_type=int)
self.general.show_update_stale = self._get_config_file_value(config_object, 'General', 'showupdate_stale', default=self.general.show_update_stale,
field_type=bool)
self.general.show_update_hour = self._get_config_file_value(config_object, 'General', 'showupdate_hour', default=self.general.show_update_hour,
field_type=int)
self.general.backlog_days = self._get_config_file_value(config_object, 'General', 'backlog_days', default=self.general.backlog_days, field_type=int)
self.general.auto_postprocessor_freq = self._get_config_file_value(config_object, 'General', 'autopostprocessor_frequency',
default=self.general.auto_postprocessor_freq, field_type=int)
self.general.tv_download_dir = self._get_config_file_value(config_object, 'General', 'tv_download_dir', default=self.general.tv_download_dir,
field_type=str)
self.general.process_automatically = self._get_config_file_value(config_object, 'General', 'process_automatically',
default=self.general.process_automatically, field_type=bool)
self.general.no_delete = self._get_config_file_value(config_object, 'General', 'no_delete', default=self.general.no_delete, field_type=bool)
self.general.unpack = self._get_config_file_value(config_object, 'General', 'unpack', default=self.general.unpack, field_type=bool)
self.general.unpack_dir = self._get_config_file_value(config_object, 'General', 'unpack_dir', default=self.general.unpack_dir, field_type=str)
self.general.rename_episodes = self._get_config_file_value(config_object, 'General', 'rename_episodes', default=self.general.rename_episodes,
field_type=bool)
self.general.airdate_episodes = self._get_config_file_value(config_object, 'General', 'airdate_episodes', default=self.general.airdate_episodes,
field_type=bool)
self.general.file_timestamp_timezone = FileTimestampTimezone[
self._get_config_file_value(config_object, 'General', 'file_timestamp_timezone', default=FileTimestampTimezone.NETWORK.name,
field_type=str.upper)]
self.general.keep_processed_dir = self._get_config_file_value(config_object, 'General', 'keep_processed_dir', default=self.general.keep_processed_dir,
field_type=bool)
self.general.process_method = ProcessMethod[
self._get_config_file_value(config_object, 'General', 'process_method', default=ProcessMethod.COPY.name, field_type=str.upper)]
self.general.processor_follow_symlinks = self._get_config_file_value(config_object, 'General', 'processor_follow_symlinks',
default=self.general.processor_follow_symlinks, field_type=bool)
self.general.del_rar_contents = self._get_config_file_value(config_object, 'General', 'del_rar_contents', default=self.general.del_rar_contents,
field_type=bool)
self.general.delete_non_associated_files = self._get_config_file_value(config_object, 'General', 'delete_non_associated_files',
default=self.general.delete_non_associated_files, field_type=bool)
self.general.move_associated_files = self._get_config_file_value(config_object, 'General', 'move_associated_files',
default=self.general.move_associated_files, field_type=bool)
self.general.postpone_if_sync_files = self._get_config_file_value(config_object, 'General', 'postpone_if_sync_files',
default=self.general.postpone_if_sync_files, field_type=bool)
self.general.sync_files = self._get_config_file_value(config_object, 'General', 'sync_files', default=self.general.sync_files, field_type=str)
self.general.nfo_rename = self._get_config_file_value(config_object, 'General', 'nfo_rename', default=self.general.nfo_rename, field_type=bool)
self.general.create_missing_show_dirs = self._get_config_file_value(config_object, 'General', 'create_missing_show_dirs',
default=self.general.create_missing_show_dirs, field_type=bool)
self.general.add_shows_wo_dir = self._get_config_file_value(config_object, 'General', 'add_shows_wo_dir', default=self.general.add_shows_wo_dir,
field_type=bool)
self.general.require_words = self._get_config_file_value(config_object, 'General', 'require_words', default=self.general.require_words, field_type=str)
self.general.ignore_words = self._get_config_file_value(config_object, 'General', 'ignore_words', default=self.general.ignore_words, field_type=str)
self.general.ignored_subs_list = self._get_config_file_value(config_object, 'General', 'ignored_subs_list', default=self.general.ignored_subs_list,
field_type=str)
self.general.calendar_unprotected = self._get_config_file_value(config_object, 'General', 'calendar_unprotected',
default=self.general.calendar_unprotected, field_type=bool)
self.general.calendar_icons = self._get_config_file_value(config_object, 'General', 'calendar_icons', default=self.general.calendar_icons,
field_type=bool)
self.general.no_restart = self._get_config_file_value(
config_object,
'General',
'no_restart',
default=self.general.no_restart,
field_type=bool
)
self.general.allowed_video_file_exts = ','.join(
self._get_config_file_value(
config_object,
'General',
'allowed_video_file_exts',
default=self.general.allowed_video_file_exts.split(','),
field_type=list
)
)
self.general.extra_scripts = self._get_config_file_value(config_object, 'General', 'extra_scripts', default=self.general.extra_scripts, field_type=str)
self.general.display_all_seasons = self._get_config_file_value(config_object, 'General', 'display_all_seasons',
default=self.general.display_all_seasons, field_type=bool)
self.general.random_user_agent = self._get_config_file_value(config_object, 'General', 'random_user_agent', default=self.general.random_user_agent,
field_type=bool)
self.general.allowed_extensions = self._get_config_file_value(config_object, 'General', 'allowed_extensions', default=self.general.allowed_extensions,
field_type=str)
self.general.view_changelog = self._get_config_file_value(config_object, 'General', 'view_changelog', default=self.general.view_changelog,
field_type=bool)
self.general.strip_special_file_bits = self._get_config_file_value(config_object, 'General', 'strip_special_file_bits',
default=self.general.strip_special_file_bits, field_type=bool)
# GUI SETTINGS
self.gui.gui_lang = self._get_config_file_value(config_object, 'GUI', 'gui_lang', default=self.gui.gui_lang, field_type=str)
self.gui.theme_name = UITheme[
self._get_config_file_value(config_object, 'GUI', 'theme_name', default=UITheme.DARK.name, field_type=str.upper)]
self.gui.fanart_background = self._get_config_file_value(config_object, 'GUI', 'fanart_background', default=self.gui.fanart_background, field_type=bool)
self.gui.fanart_background_opacity = self._get_config_file_value(config_object, 'GUI', 'fanart_background_opacity',
default=self.gui.fanart_background_opacity, field_type=float)
self.gui.home_layout = HomeLayout[
self._get_config_file_value(config_object, 'GUI', 'home_layout', default=HomeLayout.POSTER.name, field_type=str.upper)]
self.gui.history_layout = HistoryLayout[
self._get_config_file_value(config_object, 'GUI', 'history_layout', default=HistoryLayout.DETAILED.name, field_type=str.upper)]
self.gui.history_limit = self._get_config_file_value(config_object, 'GUI', 'history_limit', default=self.gui.history_limit, field_type=int)
self.gui.display_show_specials = self._get_config_file_value(config_object, 'GUI', 'display_show_specials', default=self.gui.display_show_specials,
field_type=bool)
self.gui.coming_eps_layout = ComingEpsLayout[
self._get_config_file_value(config_object, 'GUI', 'coming_eps_layout', default=ComingEpsLayout.POSTER.name, field_type=str.upper)]
self.gui.coming_eps_display_paused = self._get_config_file_value(config_object, 'GUI', 'coming_eps_display_paused',
default=self.gui.coming_eps_display_paused, field_type=bool)
self.gui.coming_eps_sort = ComingEpsSortBy[
self._get_config_file_value(config_object, 'GUI', 'coming_eps_sort', default=ComingEpsSortBy.DATE.name, field_type=str.upper)]
self.gui.coming_eps_missed_range = self._get_config_file_value(config_object, 'GUI', 'coming_eps_missed_range',
default=self.gui.coming_eps_missed_range, field_type=int)
self.gui.fuzzy_dating = self._get_config_file_value(config_object, 'GUI', 'fuzzy_dating', default=self.gui.fuzzy_dating, field_type=bool)
self.gui.trim_zero = self._get_config_file_value(config_object, 'GUI', 'trim_zero', default=self.gui.trim_zero, field_type=bool)
self.gui.date_preset = self._get_config_file_value(config_object, 'GUI', 'date_preset', default=self.gui.date_preset, field_type=str)
self.gui.time_preset_w_seconds = self._get_config_file_value(config_object, 'GUI', 'time_preset', default=self.gui.time_preset_w_seconds,
field_type=str)
self.gui.time_preset = self.gui.time_preset_w_seconds.replace(":%S", "")
self.gui.timezone_display = TimezoneDisplay[
self._get_config_file_value(config_object, 'GUI', 'timezone_display', default=TimezoneDisplay.NETWORK.name, field_type=str.upper)]
self.gui.poster_sort_by = PosterSortBy[
self._get_config_file_value(config_object, 'GUI', 'poster_sortby', default=PosterSortBy.NAME.name, field_type=str.upper)]
self.gui.poster_sort_dir = PosterSortDirection(
self._get_config_file_value(config_object, 'GUI', 'poster_sortdir', default=self.gui.poster_sort_dir, field_type=int))
self.gui.filter_row = self._get_config_file_value(config_object, 'GUI', 'filter_row', default=self.gui.filter_row, field_type=bool)
# BLACKHOLE SETTINGS
self.blackhole.nzb_dir = self._get_config_file_value(config_object, 'Blackhole', 'nzb_dir', default=self.blackhole.nzb_dir, field_type=str)
self.blackhole.torrent_dir = self._get_config_file_value(config_object, 'Blackhole', 'torrent_dir', default=self.blackhole.torrent_dir, field_type=str)
# SABNZBD SETTINGS
self.sabnzbd.username = self._get_config_file_value(config_object, 'SABnzbd', 'sab_username', default=self.sabnzbd.username, field_type=str)
self.sabnzbd.password = self._get_config_file_value(config_object, 'SABnzbd', 'sab_password', default=self.sabnzbd.password, field_type=str)
self.sabnzbd.apikey = self._get_config_file_value(config_object, 'SABnzbd', 'sab_apikey', default=self.sabnzbd.apikey, field_type=str)
self.sabnzbd.category = self._get_config_file_value(config_object, 'SABnzbd', 'sab_category', default=self.sabnzbd.category, field_type=str)
self.sabnzbd.category_backlog = self._get_config_file_value(config_object, 'SABnzbd', 'sab_category_backlog', default=self.sabnzbd.category_backlog,
field_type=str)
self.sabnzbd.category_anime = self._get_config_file_value(config_object, 'SABnzbd', 'sab_category_anime', default=self.sabnzbd.category_anime,
field_type=str)
self.sabnzbd.category_anime_backlog = self._get_config_file_value(config_object, 'SABnzbd', 'sab_category_anime_backlog',
default=self.sabnzbd.category_anime_backlog, field_type=str)
self.sabnzbd.host = self._get_config_file_value(config_object, 'SABnzbd', 'sab_host', default=self.sabnzbd.host, field_type=str)
self.sabnzbd.forced = self._get_config_file_value(config_object, 'SABnzbd', 'sab_forced', default=self.sabnzbd.forced, field_type=bool)
# NZBGET SETTINGS
self.nzbget.username = self._get_config_file_value(config_object, 'NZBget', 'nzbget_username', default=self.nzbget.username, field_type=str)
self.nzbget.password = self._get_config_file_value(config_object, 'NZBget', 'nzbget_password', default=self.nzbget.password, field_type=str)
self.nzbget.category = self._get_config_file_value(config_object, 'NZBget', 'nzbget_category', default=self.nzbget.category, field_type=str)
self.nzbget.category_backlog = self._get_config_file_value(config_object, 'NZBget', 'nzbget_category_backlog', default=self.nzbget.category_backlog,
field_type=str)
self.nzbget.category_anime = self._get_config_file_value(config_object, 'NZBget', 'nzbget_category_anime', default=self.nzbget.category_anime,
field_type=str)
self.nzbget.category_anime_backlog = self._get_config_file_value(config_object, 'NZBget', 'nzbget_category_anime_backlog',
default=self.nzbget.category_anime_backlog, field_type=str)
self.nzbget.host = self._get_config_file_value(config_object, 'NZBget', 'nzbget_host', default=self.nzbget.host, field_type=str)
self.nzbget.use_https = self._get_config_file_value(config_object, 'NZBget', 'nzbget_use_https', default=self.nzbget.use_https, field_type=bool)
self.nzbget.priority = self._get_config_file_value(config_object, 'NZBget', 'nzbget_priority', default=self.nzbget.priority, field_type=int)
# TORRENT SETTINGS
self.torrent.username = self._get_config_file_value(config_object, 'TORRENT', 'torrent_username', default=self.torrent.username, field_type=str)
self.torrent.password = self._get_config_file_value(config_object, 'TORRENT', 'torrent_password', default=self.torrent.password, field_type=str)
self.torrent.host = self._get_config_file_value(config_object, 'TORRENT', 'torrent_host', default=self.torrent.host, field_type=str)
self.torrent.path = self._get_config_file_value(config_object, 'TORRENT', 'torrent_path', default=self.torrent.path, field_type=str)
self.torrent.seed_time = self._get_config_file_value(config_object, 'TORRENT', 'torrent_seed_time', default=self.torrent.seed_time, field_type=int)
self.torrent.paused = self._get_config_file_value(config_object, 'TORRENT', 'torrent_paused', default=self.torrent.paused, field_type=bool)
self.torrent.high_bandwidth = self._get_config_file_value(config_object, 'TORRENT', 'torrent_high_bandwidth', default=self.torrent.high_bandwidth,
field_type=bool)
self.torrent.label = self._get_config_file_value(config_object, 'TORRENT', 'torrent_label', default=self.torrent.label, field_type=str)
self.torrent.label_anime = self._get_config_file_value(config_object, 'TORRENT', 'torrent_label_anime', default=self.torrent.label_anime,
field_type=str)
self.torrent.verify_cert = self._get_config_file_value(config_object, 'TORRENT', 'torrent_verify_cert', default=self.torrent.verify_cert,
field_type=bool)
self.torrent.rpc_url = self._get_config_file_value(config_object, 'TORRENT', 'torrent_rpcurl', default=self.torrent.rpc_url, field_type=str)
self.torrent.auth_type = self._get_config_file_value(config_object, 'TORRENT', 'torrent_auth_type', default=self.torrent.auth_type, field_type=str)
# KODI SETTINGS
self.kodi.enable = self._get_config_file_value(config_object, 'KODI', 'use_kodi', default=self.kodi.enable, field_type=bool)
self.kodi.always_on = self._get_config_file_value(config_object, 'KODI', 'kodi_always_on', default=self.kodi.always_on, field_type=bool)
self.kodi.notify_on_snatch = self._get_config_file_value(config_object, 'KODI', 'kodi_notify_onsnatch', default=self.kodi.notify_on_snatch,
field_type=bool)
self.kodi.notify_on_download = self._get_config_file_value(config_object, 'KODI', 'kodi_notify_ondownload', default=self.kodi.notify_on_download,
field_type=bool)
self.kodi.notify_on_subtitle_download = self._get_config_file_value(config_object, 'KODI', 'kodi_notify_onsubtitledownload',
default=self.kodi.notify_on_subtitle_download, field_type=bool)
self.kodi.update_library = self._get_config_file_value(config_object, 'KODI', 'kodi_update_library', default=self.kodi.update_library, field_type=bool)
self.kodi.update_full = self._get_config_file_value(config_object, 'KODI', 'kodi_update_full', default=self.kodi.update_full, field_type=bool)
self.kodi.update_only_first = self._get_config_file_value(config_object, 'KODI', 'kodi_update_onlyfirst', default=self.kodi.update_only_first,
field_type=bool)
self.kodi.host = self._get_config_file_value(config_object, 'KODI', 'kodi_host', default=self.kodi.host, field_type=str)
self.kodi.username = self._get_config_file_value(config_object, 'KODI', 'kodi_username', default=self.kodi.username, field_type=str)
self.kodi.password = self._get_config_file_value(config_object, 'KODI', 'kodi_password', default=self.kodi.password, field_type=str)
# PLEX SETTINGS
self.plex.enable = self._get_config_file_value(config_object, 'Plex', 'use_plex', default=self.plex.enable, field_type=bool)
self.plex.notify_on_snatch = self._get_config_file_value(config_object, 'Plex', 'plex_notify_onsnatch', default=self.plex.notify_on_snatch,
field_type=bool)
self.plex.notify_on_download = self._get_config_file_value(config_object, 'Plex', 'plex_notify_ondownload', default=self.plex.notify_on_download,
field_type=bool)
self.plex.notify_on_subtitle_download = self._get_config_file_value(config_object, 'Plex', 'plex_notify_onsubtitledownload',
default=self.plex.notify_on_subtitle_download, field_type=bool)
self.plex.update_library = self._get_config_file_value(config_object, 'Plex', 'plex_update_library', default=self.plex.update_library, field_type=bool)
self.plex.server_host = self._get_config_file_value(config_object, 'Plex', 'plex_server_host', default=self.plex.server_host, field_type=str)
self.plex.server_token = self._get_config_file_value(config_object, 'Plex', 'plex_server_token', default=self.plex.server_token, field_type=str)
self.plex.host = self._get_config_file_value(config_object, 'Plex', 'plex_host', default=self.plex.host, field_type=str)
self.plex.username = self._get_config_file_value(config_object, 'Plex', 'plex_username', default=self.plex.username, field_type=str)
self.plex.password = self._get_config_file_value(config_object, 'Plex', 'plex_password', default=self.plex.password, field_type=str)
self.plex.enable_client = self._get_config_file_value(config_object, 'Plex', 'use_plex_client', default=self.plex.enable_client, field_type=bool)
self.plex.client_username = self._get_config_file_value(config_object, 'Plex', 'plex_client_username', default=self.plex.client_username,
field_type=str)
self.plex.client_password = self._get_config_file_value(config_object, 'Plex', 'plex_client_password', default=self.plex.client_password,
field_type=str)
# EMBY SETTINGS
self.emby.enable = self._get_config_file_value(config_object, 'Emby', 'use_emby', default=self.emby.enable, field_type=bool)
self.emby.notify_on_snatch = self._get_config_file_value(config_object, 'Emby', 'emby_notify_onsnatch', default=self.emby.notify_on_snatch,
field_type=bool)
self.emby.notify_on_download = self._get_config_file_value(config_object, 'Emby', 'emby_notify_ondownload', default=self.emby.notify_on_download,
field_type=bool)
self.emby.notify_on_subtitle_download = self._get_config_file_value(config_object, 'Emby', 'emby_notify_onsubtitledownload',
default=self.emby.notify_on_subtitle_download, field_type=bool)
self.emby.host = self._get_config_file_value(config_object, 'Emby', 'emby_host', default=self.emby.host, field_type=str)
self.emby.apikey = self._get_config_file_value(config_object, 'Emby', 'emby_apikey', default=self.emby.apikey, field_type=str)
# GROWL SETTINGS
self.growl.enable = self._get_config_file_value(config_object, 'Growl', 'use_growl', default=self.growl.enable, field_type=bool)
self.growl.notify_on_snatch = self._get_config_file_value(config_object, 'Growl', 'growl_notify_onsnatch', default=self.growl.notify_on_snatch,
field_type=bool)
self.growl.notify_on_download = self._get_config_file_value(config_object, 'Growl', 'growl_notify_ondownload', default=self.growl.notify_on_download,
field_type=bool)
self.growl.notify_on_subtitle_download = self._get_config_file_value(config_object, 'Growl', 'growl_notify_onsubtitledownload',
default=self.growl.notify_on_subtitle_download, field_type=bool)
self.growl.host = self._get_config_file_value(config_object, 'Growl', 'growl_host', default=self.growl.host, field_type=str)
self.growl.password = self._get_config_file_value(config_object, 'Growl', 'growl_password', default=self.growl.password, field_type=str)
# FREEMOBILE SETTINGS
self.freemobile.enable = self._get_config_file_value(config_object, 'FreeMobile', 'use_freemobile', default=self.freemobile.enable, field_type=bool)
self.freemobile.notify_on_snatch = self._get_config_file_value(config_object, 'FreeMobile', 'freemobile_notify_onsnatch',
default=self.freemobile.notify_on_snatch, field_type=bool)
self.freemobile.notify_on_download = self._get_config_file_value(config_object, 'FreeMobile', 'freemobile_notify_ondownload',
default=self.freemobile.notify_on_download, field_type=bool)
self.freemobile.notify_on_subtitle_download = self._get_config_file_value(config_object, 'FreeMobile', 'freemobile_notify_onsubtitledownload',
field_type=bool)
self.freemobile.user_id = self._get_config_file_value(config_object, 'FreeMobile', 'freemobile_id', default=self.freemobile.user_id, field_type=str)
self.freemobile.apikey = self._get_config_file_value(config_object, 'FreeMobile', 'freemobile_apikey', default=self.freemobile.apikey, field_type=str)
# TELEGRAM SETTINGS
self.telegram.enable = self._get_config_file_value(config_object, 'TELEGRAM', 'use_telegram', default=self.telegram.enable, field_type=bool)
self.telegram.notify_on_snatch = self._get_config_file_value(config_object, 'TELEGRAM', 'telegram_notify_onsnatch',
default=self.telegram.notify_on_snatch, field_type=bool)
self.telegram.notify_on_download = self._get_config_file_value(config_object, 'TELEGRAM', 'telegram_notify_ondownload',
default=self.telegram.notify_on_download, field_type=bool)
self.telegram.notify_on_subtitle_download = self._get_config_file_value(config_object, 'TELEGRAM', 'telegram_notify_on_subtitledownload',
field_type=bool)
self.telegram.user_id = self._get_config_file_value(config_object, 'TELEGRAM', 'telegram_id', default=self.telegram.user_id, field_type=str)
self.telegram.apikey = self._get_config_file_value(config_object, 'TELEGRAM', 'telegram_apikey', default=self.telegram.apikey, field_type=str)
# JOIN SETTINGS
self.join_app.enable = self._get_config_file_value(config_object, 'JOIN', 'use_join', default=self.join_app.enable, field_type=bool)
self.join_app.notify_on_snatch = self._get_config_file_value(config_object, 'JOIN', 'join_notify_onsnatch', default=self.join_app.notify_on_snatch,
field_type=bool)
self.join_app.notify_on_download = self._get_config_file_value(config_object, 'JOIN', 'join_notify_ondownload',
default=self.join_app.notify_on_download, field_type=bool)
self.join_app.notify_on_subtitle_download = self._get_config_file_value(config_object, 'JOIN', 'join_notify_onsubtitledownload',
default=self.join_app.notify_on_subtitle_download, field_type=bool)
self.join_app.user_id = self._get_config_file_value(config_object, 'JOIN', 'join_id', default=self.join_app.user_id, field_type=str)
self.join_app.apikey = self._get_config_file_value(config_object, 'JOIN', 'join_apikey', default=self.join_app.apikey, field_type=str)
# PROWL SETTINGS
self.prowl.enable = self._get_config_file_value(config_object, 'Prowl', 'use_prowl', default=self.prowl.enable, field_type=bool)
self.prowl.notify_on_snatch = self._get_config_file_value(config_object, 'Prowl', 'prowl_notify_onsnatch', default=self.prowl.notify_on_snatch,
field_type=bool)
self.prowl.notify_on_download = self._get_config_file_value(config_object, 'Prowl', 'prowl_notify_ondownload', default=self.prowl.notify_on_download,
field_type=bool)
self.prowl.notify_on_subtitle_download = self._get_config_file_value(config_object, 'Prowl', 'prowl_notify_onsubtitledownload',
default=self.prowl.notify_on_subtitle_download, field_type=bool)
self.prowl.apikey = self._get_config_file_value(config_object, 'Prowl', 'prowl_api', default=self.prowl.apikey, field_type=str)
self.prowl.priority = self._get_config_file_value(config_object, 'Prowl', 'prowl_priority', default=self.prowl.priority, field_type=int)
# TWITTER SETTINGS
self.twitter.enable = self._get_config_file_value(config_object, 'Twitter', 'use_twitter', default=self.twitter.enable, field_type=bool)
self.twitter.notify_on_snatch = self._get_config_file_value(config_object, 'Twitter', 'twitter_notify_onsnatch', default=self.twitter.notify_on_snatch,
field_type=bool)
self.twitter.notify_on_download = self._get_config_file_value(config_object, 'Twitter', 'twitter_notify_ondownload',
default=self.twitter.notify_on_download, field_type=bool)
self.twitter.notify_on_subtitle_download = self._get_config_file_value(config_object, 'Twitter', 'twitter_notify_onsubtitledownload',
field_type=bool)
self.twitter.username = self._get_config_file_value(config_object, 'Twitter', 'twitter_username', default=self.twitter.username, field_type=str)
self.twitter.password = self._get_config_file_value(config_object, 'Twitter', 'twitter_password', default=self.twitter.password, field_type=str)
self.twitter.prefix = self._get_config_file_value(config_object, 'Twitter', 'twitter_prefix', default=self.twitter.prefix, field_type=str)
self.twitter.dm_to = self._get_config_file_value(config_object, 'Twitter', 'twitter_dmto', default=self.twitter.dm_to, field_type=str)
self.twitter.use_dm = self._get_config_file_value(config_object, 'Twitter', 'twitter_usedm', default=self.twitter.use_dm, field_type=bool)
# TWIILIO SETTINGS
self.twilio.enable = self._get_config_file_value(config_object, 'Twilio', 'use_twilio', default=self.twilio.enable, field_type=bool)
self.twilio.notify_on_snatch = self._get_config_file_value(config_object, 'Twilio', 'twilio_notify_onsnatch', default=self.twilio.notify_on_snatch,
field_type=bool)
self.twilio.notify_on_download = self._get_config_file_value(config_object, 'Twilio', 'twilio_notify_ondownload',
default=self.twilio.notify_on_download, field_type=bool)
self.twilio.notify_on_subtitle_download = self._get_config_file_value(config_object, 'Twilio', 'twilio_notify_onsubtitledownload',
field_type=bool)
self.twilio.phone_sid = self._get_config_file_value(config_object, 'Twilio', 'twilio_phone_sid', default=self.twilio.phone_sid, field_type=str)
self.twilio.account_sid = self._get_config_file_value(config_object, 'Twilio', 'twilio_account_sid', default=self.twilio.account_sid, field_type=str)
self.twilio.auth_token = self._get_config_file_value(config_object, 'Twilio', 'twilio_auth_token', default=self.twilio.auth_token, field_type=str)
self.twilio.to_number = self._get_config_file_value(config_object, 'Twilio', 'twilio_to_number', default=self.twilio.to_number, field_type=str)
# BOXCAR2 SETTINGS
self.boxcar2.enable = self._get_config_file_value(config_object, 'Boxcar2', 'use_boxcar2', default=self.boxcar2.enable, field_type=bool)
self.boxcar2.notify_on_snatch = self._get_config_file_value(config_object, 'Boxcar2', 'boxcar2_notify_onsnatch', default=self.boxcar2.notify_on_snatch,
field_type=bool)
self.boxcar2.notify_on_download = self._get_config_file_value(config_object, 'Boxcar2', 'boxcar2_notify_ondownload',
default=self.boxcar2.notify_on_download, field_type=bool)
self.boxcar2.notify_on_subtitle_download = self._get_config_file_value(config_object, 'Boxcar2', 'boxcar2_notify_onsubtitledownload',
default=self.boxcar2.notify_on_subtitle_download, field_type=bool)
self.boxcar2.access_token = self._get_config_file_value(config_object, 'Boxcar2', 'boxcar2_accesstoken', default=self.boxcar2.access_token,
field_type=str)
# PUSHOVER SETTINGS
self.pushover.enable = self._get_config_file_value(config_object, 'Pushover', 'use_pushover', default=self.pushover.enable, field_type=bool)
self.pushover.notify_on_snatch = self._get_config_file_value(config_object, 'Pushover', 'pushover_notify_onsnatch',
default=self.pushover.notify_on_snatch, field_type=bool)
self.pushover.notify_on_download = self._get_config_file_value(config_object, 'Pushover', 'pushover_notify_ondownload',
default=self.pushover.notify_on_download, field_type=bool)
self.pushover.notify_on_subtitle_download = self._get_config_file_value(config_object, 'Pushover', 'pushover_notify_onsubtitledownload',
field_type=bool)
self.pushover.user_key = self._get_config_file_value(config_object, 'Pushover', 'pushover_userkey', default=self.pushover.user_key, field_type=str)
self.pushover.apikey = self._get_config_file_value(config_object, 'Pushover', 'pushover_apikey', default=self.pushover.apikey, field_type=str)
self.pushover.device = self._get_config_file_value(config_object, 'Pushover', 'pushover_device', default=self.pushover.device, field_type=str)
self.pushover.sound = self._get_config_file_value(config_object, 'Pushover', 'pushover_sound', default=self.pushover.sound, field_type=str)
# LIBNOTIFY SETTINGS
self.libnotify.enable = self._get_config_file_value(config_object, 'Libnotify', 'use_libnotify', default=self.libnotify.enable, field_type=bool)
self.libnotify.notify_on_snatch = self._get_config_file_value(config_object, 'Libnotify', 'libnotify_notify_onsnatch',
default=self.libnotify.notify_on_snatch, field_type=bool)
self.libnotify.notify_on_download = self._get_config_file_value(config_object, 'Libnotify', 'libnotify_notify_ondownload',
default=self.libnotify.notify_on_download, field_type=bool)
self.libnotify.notify_on_subtitle_download = self._get_config_file_value(config_object, 'Libnotify', 'libnotify_notify_onsubtitledownload',
field_type=bool)
# NMJ SETTINGS
self.nmj.enable = self._get_config_file_value(config_object, 'NMJ', 'use_nmj', default=self.nmj.enable, field_type=bool)
self.nmj.host = self._get_config_file_value(config_object, 'NMJ', 'nmj_host', default=self.nmj.host, field_type=str)
self.nmj.database = self._get_config_file_value(config_object, 'NMJ', 'nmj_database', default=self.nmj.database, field_type=str)
self.nmj.mount = self._get_config_file_value(config_object, 'NMJ', 'nmj_mount', default=self.nmj.mount, field_type=str)
# NMJV2 SETTINGS
self.nmjv2.enable = self._get_config_file_value(config_object, 'NMJv2', 'use_nmjv2', default=self.nmjv2.enable, field_type=bool)
self.nmjv2.host = self._get_config_file_value(config_object, 'NMJv2', 'nmjv2_host', default=self.nmjv2.host, field_type=str)
self.nmjv2.database = self._get_config_file_value(config_object, 'NMJv2', 'nmjv2_database', default=self.nmjv2.database, field_type=str)
self.nmjv2.db_loc = NMJv2Location[self._get_config_file_value(config_object, 'NMJv2', 'nmjv2_dbloc', default=NMJv2Location.LOCAL.name, field_type=str.upper)]
# SYNOLOGY SETTINGS
self.synology.host = self._get_config_file_value(config_object, 'SynologyDSM', 'syno_dsm_host', default=self.synology.host, field_type=str)
self.synology.username = self._get_config_file_value(config_object, 'SynologyDSM', 'syno_dsm_username', default=self.synology.username, field_type=str)
self.synology.password = self._get_config_file_value(config_object, 'SynologyDSM', 'syno_dsm_password', default=self.synology.password, field_type=str)
self.synology.path = self._get_config_file_value(config_object, 'SynologyDSM', 'syno_dsm_path', default=self.synology.path, field_type=str)
self.synology.enable_index = self._get_config_file_value(config_object, 'Synology', 'use_synoindex', default=self.synology.enable_index,
field_type=bool)
self.synology.enable_notifications = self._get_config_file_value(config_object, 'SynologyNotifier', 'use_synologynotifier',
default=self.synology.enable_notifications, field_type=bool)
self.synology.notify_on_snatch = self._get_config_file_value(config_object, 'SynologyNotifier', 'synologynotifier_notify_onsnatch',
field_type=bool)
self.synology.notify_on_download = self._get_config_file_value(config_object, 'SynologyNotifier', 'synologynotifier_notify_ondownload',
field_type=bool)
self.synology.notify_on_subtitle_download = self._get_config_file_value(config_object, 'SynologyNotifier',
'synologynotifier_notify_onsubtitledownload', field_type=bool)
# SLACK SETTINGS
self.slack.enable = self._get_config_file_value(config_object, 'Slack', 'use_slack', default=self.slack.enable, field_type=bool)
self.slack.notify_on_snatch = self._get_config_file_value(config_object, 'Slack', 'slack_notify_onsnatch', default=self.slack.notify_on_snatch,
field_type=bool)
self.slack.notify_on_download = self._get_config_file_value(config_object, 'Slack', 'slack_notify_ondownload', default=self.slack.notify_on_download,
field_type=bool)
self.slack.notify_on_subtitle_download = self._get_config_file_value(config_object, 'Slack', 'slack_notify_onsubtitledownload',
default=self.slack.notify_on_subtitle_download, field_type=bool)
self.slack.webhook = self._get_config_file_value(config_object, 'Slack', 'slack_webhook', default=self.slack.webhook, field_type=str)
# DISCORD SETTINGS
self.discord.enable = self._get_config_file_value(config_object, 'Discord', 'use_discord', default=self.discord.enable, field_type=bool)
self.discord.notify_on_snatch = self._get_config_file_value(config_object, 'Discord', 'discord_notify_onsnatch', default=self.discord.notify_on_snatch,
field_type=bool)
self.discord.notify_on_download = self._get_config_file_value(config_object, 'Discord', 'discord_notify_ondownload',
default=self.discord.notify_on_download, field_type=bool)
self.discord.notify_on_subtitle_download = self._get_config_file_value(config_object, 'Discord', 'discord_notify_onsubtitledownload',
field_type=bool)
self.discord.webhook = self._get_config_file_value(config_object, 'Discord', 'discord_webhook', default=self.discord.webhook, field_type=str)
self.discord.avatar_url = self._get_config_file_value(config_object, 'Discord', 'discord_avatar_url', default=self.discord.avatar_url, field_type=str)
self.discord.name = self._get_config_file_value(config_object, 'Discord', 'discord_name', default=self.discord.name, field_type=str)
self.discord.tts = self._get_config_file_value(config_object, 'Discord', 'discord_tts', default=self.discord.tts, field_type=bool)
# TRAKT SETTINGS
self.trakt.enable = self._get_config_file_value(config_object, 'Trakt', 'use_trakt', default=self.trakt.enable, field_type=bool)
self.trakt.username = self._get_config_file_value(config_object, 'Trakt', 'trakt_username', default=self.trakt.username, field_type=str)
self.trakt.remove_watchlist = self._get_config_file_value(config_object, 'Trakt', 'trakt_remove_watchlist', default=self.trakt.remove_watchlist,
field_type=bool)
self.trakt.remove_serieslist = self._get_config_file_value(config_object, 'Trakt', 'trakt_remove_serieslist', default=self.trakt.remove_serieslist,
field_type=bool)
self.trakt.remove_show_from_sickrage = self._get_config_file_value(config_object, 'Trakt', 'trakt_remove_show_from_sickrage',
default=self.trakt.remove_show_from_sickrage, field_type=bool)
self.trakt.sync_watchlist = self._get_config_file_value(config_object, 'Trakt', 'trakt_sync_watchlist', default=self.trakt.sync_watchlist,
field_type=bool)
self.trakt.method_add = TraktAddMethod(
self._get_config_file_value(config_object, 'Trakt', 'trakt_method_add', default=self.trakt.method_add, field_type=int))
self.trakt.start_paused = self._get_config_file_value(config_object, 'Trakt', 'trakt_start_paused', default=self.trakt.start_paused, field_type=bool)
self.trakt.use_recommended = self._get_config_file_value(config_object, 'Trakt', 'trakt_use_recommended', default=self.trakt.use_recommended,
field_type=bool)
self.trakt.sync = self._get_config_file_value(config_object, 'Trakt', 'trakt_sync', default=self.trakt.sync, field_type=bool)
self.trakt.sync_remove = self._get_config_file_value(config_object, 'Trakt', 'trakt_sync_remove', default=self.trakt.sync_remove, field_type=bool)
self.trakt.series_provider_default = SeriesProviderID.THETVDB
self.trakt.timeout = self._get_config_file_value(config_object, 'Trakt', 'trakt_timeout', default=self.trakt.timeout, field_type=int)
self.trakt.blacklist_name = self._get_config_file_value(config_object, 'Trakt', 'trakt_blacklist_name', default=self.trakt.blacklist_name,
field_type=str)
# PYTIVO SETTINGS
self.pytivo.enable = self._get_config_file_value(config_object, 'pyTivo', 'use_pytivo', default=self.pytivo.enable, field_type=bool)
self.pytivo.notify_on_snatch = self._get_config_file_value(config_object, 'pyTivo', 'pytivo_notify_onsnatch', default=self.pytivo.notify_on_snatch,
field_type=bool)
self.pytivo.notify_on_download = self._get_config_file_value(config_object, 'pyTivo', 'pytivo_notify_ondownload',
default=self.pytivo.notify_on_download, field_type=bool)
self.pytivo.notify_on_subtitle_download = self._get_config_file_value(config_object, 'pyTivo', 'pytivo_notify_onsubtitledownload',
field_type=bool)
self.pytivo.update_library = self._get_config_file_value(config_object, 'pyTivo', 'pyTivo_update_library', default=self.pytivo.update_library,
field_type=bool)
self.pytivo.host = self._get_config_file_value(config_object, 'pyTivo', 'pytivo_host', default=self.pytivo.host, field_type=str)
self.pytivo.share_name = self._get_config_file_value(config_object, 'pyTivo', 'pytivo_share_name', default=self.pytivo.share_name, field_type=str)
self.pytivo.tivo_name = self._get_config_file_value(config_object, 'pyTivo', 'pytivo_tivo_name', default=self.pytivo.tivo_name, field_type=str)
# NMA SETTINGS
self.nma.enable = self._get_config_file_value(config_object, 'NMA', 'use_nma', default=self.nma.enable, field_type=bool)
self.nma.notify_on_snatch = self._get_config_file_value(config_object, 'NMA', 'nma_notify_onsnatch', default=self.nma.notify_on_snatch, field_type=bool)
self.nma.notify_on_download = self._get_config_file_value(config_object, 'NMA', 'nma_notify_ondownload', default=self.nma.notify_on_download,
field_type=bool)
self.nma.notify_on_subtitle_download = self._get_config_file_value(config_object, 'NMA', 'nma_notify_onsubtitledownload',
default=self.nma.notify_on_subtitle_download, field_type=bool)
self.nma.api_keys = self._get_config_file_value(config_object, 'NMA', 'nma_api', default=self.nma.api_keys, field_type=str)
self.nma.priority = self._get_config_file_value(config_object, 'NMA', 'nma_priority', default=self.nma.priority, field_type=int)
# PUSHALOT SETTINGS
self.pushalot.enable = self._get_config_file_value(config_object, 'Pushalot', 'use_pushalot', default=self.pushalot.enable, field_type=bool)
self.pushalot.notify_on_snatch = self._get_config_file_value(config_object, 'Pushalot', 'pushalot_notify_onsnatch',
default=self.pushalot.notify_on_snatch, field_type=bool)
self.pushalot.notify_on_download = self._get_config_file_value(config_object, 'Pushalot', 'pushalot_notify_ondownload',
default=self.pushalot.notify_on_download, field_type=bool)
self.pushalot.notify_on_subtitle_download = self._get_config_file_value(config_object, 'Pushalot', 'pushalot_notify_onsubtitledownload',
field_type=bool)
self.pushalot.auth_token = self._get_config_file_value(config_object, 'Pushalot', 'pushalot_authorizationtoken', default=self.pushalot.auth_token,
field_type=str)
# PUSHBULLET SETTINGS
self.pushbullet.enable = self._get_config_file_value(config_object, 'Pushbullet', 'use_pushbullet', default=self.pushbullet.enable, field_type=bool)
self.pushbullet.notify_on_snatch = self._get_config_file_value(config_object, 'Pushbullet', 'pushbullet_notify_onsnatch',
default=self.pushbullet.notify_on_snatch, field_type=bool)
self.pushbullet.notify_on_download = self._get_config_file_value(config_object, 'Pushbullet', 'pushbullet_notify_ondownload',
default=self.pushbullet.notify_on_download, field_type=bool)
self.pushbullet.notify_on_subtitle_download = self._get_config_file_value(config_object, 'Pushbullet', 'pushbullet_notify_onsubtitledownload',
field_type=bool)
self.pushbullet.api_key = self._get_config_file_value(config_object, 'Pushbullet', 'pushbullet_api', default=self.pushbullet.api_key, field_type=str)
self.pushbullet.device = self._get_config_file_value(config_object, 'Pushbullet', 'pushbullet_device', default=self.pushbullet.device, field_type=str)
# EMAIL SETTINGS
self.email.enable = self._get_config_file_value(config_object, 'Email', 'use_email', default=self.email.enable, field_type=bool)
self.email.notify_on_snatch = self._get_config_file_value(config_object, 'Email', 'email_notify_onsnatch', default=self.email.notify_on_snatch,
field_type=bool)
self.email.notify_on_download = self._get_config_file_value(config_object, 'Email', 'email_notify_ondownload', default=self.email.notify_on_download,
field_type=bool)
self.email.notify_on_subtitle_download = self._get_config_file_value(config_object, 'Email', 'email_notify_onsubtitledownload',
default=self.email.notify_on_subtitle_download, field_type=bool)
self.email.host = self._get_config_file_value(config_object, 'Email', 'email_host', default=self.email.host, field_type=str)
self.email.port = self._get_config_file_value(config_object, 'Email', 'email_port', default=self.email.port, field_type=int)
self.email.tls = self._get_config_file_value(config_object, 'Email', 'email_tls', default=self.email.tls, field_type=bool)
self.email.username = self._get_config_file_value(config_object, 'Email', 'email_user', default=self.email.username, field_type=str)
self.email.password = self._get_config_file_value(config_object, 'Email', 'email_password', default=self.email.password, field_type=str)
self.email.send_from = self._get_config_file_value(config_object, 'Email', 'email_from', default=self.email.send_from, field_type=str)
self.email.send_to_list = self._get_config_file_value(config_object, 'Email', 'email_list', default=self.email.send_to_list, field_type=str)
# ALEXA SETTINGS
self.alexa.enable = self._get_config_file_value(config_object, 'Alexa', 'use_alexa', default=self.alexa.enable, field_type=bool)
self.alexa.notify_on_snatch = self._get_config_file_value(config_object, 'Alexa', 'alexa_notify_onsnatch', default=self.alexa.notify_on_snatch,
field_type=bool)
self.alexa.notify_on_download = self._get_config_file_value(config_object, 'Alexa', 'alexa_notify_ondownload', default=self.alexa.notify_on_download,
field_type=bool)
self.alexa.notify_on_subtitle_download = self._get_config_file_value(config_object, 'Alexa', 'alexa_notify_onsubtitledownload',
default=self.alexa.notify_on_subtitle_download, field_type=bool)
# SUBTITLE SETTINGS
self.subtitles.enable = self._get_config_file_value(config_object, 'Subtitles', 'use_subtitles', default=self.subtitles.enable, field_type=bool)
self.subtitles.languages = ','.join(
self._get_config_file_value(config_object, 'Subtitles', 'subtitles_languages', default=self.subtitles.languages, field_type=list))
self.subtitles.services_list = ','.join(
self._get_config_file_value(config_object, 'Subtitles', 'subtitles_services_list', default=self.subtitles.services_list, field_type=list))
self.subtitles.dir = self._get_config_file_value(config_object, 'Subtitles', 'subtitles_dir', default=self.subtitles.dir, field_type=str)
self.subtitles.default = self._get_config_file_value(config_object, 'Subtitles', 'subtitles_default', default=self.subtitles.default, field_type=bool)
self.subtitles.history = self._get_config_file_value(config_object, 'Subtitles', 'subtitles_history', default=self.subtitles.history, field_type=bool)
self.subtitles.hearing_impaired = self._get_config_file_value(config_object, 'Subtitles', 'subtitles_hearing_impaired',
default=self.subtitles.hearing_impaired, field_type=bool)
self.subtitles.enable_embedded = self._get_config_file_value(config_object, 'Subtitles', 'embedded_subtitles_all',
default=self.subtitles.enable_embedded, field_type=bool)
self.subtitles.multi = self._get_config_file_value(config_object, 'Subtitles', 'subtitles_multi', default=self.subtitles.multi, field_type=bool)
self.subtitles.services_enabled = self._get_config_file_value(config_object, 'Subtitles', 'subtitles_services_enabled',
default=self.subtitles.services_enabled, field_type=str)
self.subtitles.extra_scripts = self._get_config_file_value(config_object, 'Subtitles', 'subtitles_extra_scripts', default=self.subtitles.extra_scripts,
field_type=str)
self.subtitles.addic7ed_user = self._get_config_file_value(config_object, 'Subtitles', 'addic7ed_username', default=self.subtitles.addic7ed_user,
field_type=str)
self.subtitles.addic7ed_pass = self._get_config_file_value(config_object, 'Subtitles', 'addic7ed_password', default=self.subtitles.addic7ed_pass,
field_type=str)
self.subtitles.legendastv_user = self._get_config_file_value(config_object, 'Subtitles', 'legendastv_username', default=self.subtitles.legendastv_user,
field_type=str)
self.subtitles.legendastv_pass = self._get_config_file_value(config_object, 'Subtitles', 'legendastv_password', default=self.subtitles.legendastv_pass,
field_type=str)
self.subtitles.itasa_user = self._get_config_file_value(config_object, 'Subtitles', 'itasa_username', default=self.subtitles.itasa_user, field_type=str)
self.subtitles.itasa_pass = self._get_config_file_value(config_object, 'Subtitles', 'itasa_password', default=self.subtitles.itasa_pass, field_type=str)
self.subtitles.opensubtitles_user = self._get_config_file_value(config_object, 'Subtitles', 'opensubtitles_username',
default=self.subtitles.opensubtitles_user, field_type=str)
self.subtitles.opensubtitles_pass = self._get_config_file_value(config_object, 'Subtitles', 'opensubtitles_password',
default=self.subtitles.opensubtitles_pass, field_type=str)
# FAILED DOWNLOAD SETTINGS
self.failed_downloads.enable = self._get_config_file_value(config_object, 'FailedDownloads', 'delete_failed', default=self.failed_downloads.enable,
field_type=bool)
# FAILED SNATCH SETTINGS
self.failed_snatches.enable = self._get_config_file_value(config_object, 'FailedSnatches', 'use_failed_snatcher', default=self.failed_snatches.enable,
field_type=bool)
self.failed_snatches.age = self._get_config_file_value(config_object, 'FailedSnatches', 'failed_snatch_age', default=self.failed_snatches.age,
field_type=int)
# ANIDB SETTINGS
self.anidb.enable = self._get_config_file_value(config_object, 'ANIDB', 'use_anidb', default=self.anidb.enable, field_type=bool)
self.anidb.username = self._get_config_file_value(config_object, 'ANIDB', 'anidb_username', default=self.anidb.username, field_type=str)
self.anidb.password = self._get_config_file_value(config_object, 'ANIDB', 'anidb_password', default=self.anidb.password, field_type=str)
self.anidb.use_my_list = self._get_config_file_value(config_object, 'ANIDB', 'anidb_use_mylist', default=self.anidb.use_my_list, field_type=bool)
self.anidb.split_home = self._get_config_file_value(config_object, 'ANIME', 'anime_split_home', default=self.anidb.split_home, field_type=bool)
# CUSTOM SEARCH PROVIDERS
custom_providers = self._get_config_file_value(config_object, 'Providers', 'custom_providers', field_type=str)
for curProviderStr in custom_providers.split('!!!'):
if not len(curProviderStr):
continue
cur_provider_type, cur_provider_data = curProviderStr.split('|', 1)
if SearchProviderType(cur_provider_type) == SearchProviderType.TORRENT_RSS:
cur_name, cur_url, cur_cookies, cur_title_tag = cur_provider_data.split('|')
search_provider = TorrentRssProvider(cur_name, cur_url, cur_cookies, cur_title_tag)
sickrage.app.search_providers[search_provider.provider_type.name][search_provider.id] = search_provider
elif SearchProviderType(cur_provider_type) == SearchProviderType.NEWZNAB:
cur_name, cur_url, cur_key, cur_cat = cur_provider_data.split('|')
search_provider = NewznabProvider(cur_name, cur_url, cur_key, cur_cat)
sickrage.app.search_providers[search_provider.provider_type.name][search_provider.id] = search_provider
# SEARCH PROVIDER SETTINGS
for provider_id, provider_obj in sickrage.app.search_providers.all().items():
provider_settings = self._get_config_file_value(config_object, 'Providers', provider_id, field_type=dict)
provider_obj.enabled = auto_type(provider_settings.get('enabled', False))
provider_obj.search_mode = auto_type(provider_settings.get('search_mode', 'eponly'))
provider_obj.search_fallback = auto_type(provider_settings.get('search_fallback', False))
provider_obj.enable_daily = auto_type(provider_settings.get('enable_daily', False))
provider_obj.enable_backlog = auto_type(provider_settings.get('enable_backlog', False))
provider_obj.cookies = auto_type(provider_settings.get('cookies', ''))
if provider_obj.provider_type in [SearchProviderType.TORRENT, SearchProviderType.TORRENT_RSS]:
provider_obj.ratio = auto_type(provider_settings.get('ratio', 0) or 0)
elif provider_obj.provider_type in [SearchProviderType.NZB, SearchProviderType.NEWZNAB]:
provider_obj.username = auto_type(provider_settings.get('username', ''))
provider_obj.api_key = auto_type(provider_settings.get('api_key', ''))
provider_obj.api_key = auto_type(provider_settings.get('key', provider_obj.api_key))
custom_settings = {
'minseed': auto_type(provider_settings.get('minseed', 0)),
'minleech': auto_type(provider_settings.get('minleech', 0)),
'digest': auto_type(provider_settings.get('digest', '')),
'hash': auto_type(provider_settings.get('hash', '')),
'api_key': auto_type(provider_settings.get('api_key', '')),
'username': auto_type(provider_settings.get('username', '')),
'password': auto_type(provider_settings.get('password', '')),
'passkey': auto_type(provider_settings.get('passkey', '')),
'pin': auto_type(provider_settings.get('pin', '')),
'confirmed': auto_type(provider_settings.get('confirmed', False)),
'ranked': auto_type(provider_settings.get('ranked', False)),
'engrelease': auto_type(provider_settings.get('engrelease', False)),
'onlyspasearch': auto_type(provider_settings.get('onlyspasearch', False)),
'sorting': auto_type(provider_settings.get('sorting', 'seeders')),
'freeleech': auto_type(provider_settings.get('freeleech', False)),
'reject_m2ts': auto_type(provider_settings.get('reject_m2ts', False)),
# 'cat': int(auto_type(provider_settings.get('cat', None) or 0),
'subtitle': auto_type(provider_settings.get('subtitle', False)),
'custom_url': auto_type(provider_settings.get('custom_url', ''))
}
provider_obj.custom_settings.update((k, v) for k, v in custom_settings.items() if k in provider_obj.custom_settings)
# SEARCH PROVIDER ORDER SETTINGS
search_provider_order = self._get_config_file_value(config_object, 'Providers', 'providers_order', field_type=list)
for idx, search_provider_id in enumerate(search_provider_order):
if search_provider_id in sickrage.app.search_providers.all():
search_provider = sickrage.app.search_providers.all()[search_provider_id]
search_provider.sort_order = idx
# METADATA PROVIDER SETTINGS
for metadata_provider in self.db.session().query(self.db.MetadataProviders):
config_values = self._get_config_file_value(config_object, 'MetadataProviders', metadata_provider.provider_id, field_type=str)
if not config_values:
continue
metadata_provider.update(**{
'show_metadata': bool(int(config_values.split('|')[0])),
'episode_metadata': bool(int(config_values.split('|')[1])),
'fanart': bool(int(config_values.split('|')[2])),
'poster': bool(int(config_values.split('|')[3])),
'banner': bool(int(config_values.split('|')[4])),
'episode_thumbnails': bool(int(config_values.split('|')[5])),
'season_posters': bool(int(config_values.split('|')[6])),
'season_banners': bool(int(config_values.split('|')[7])),
'season_all_poster': bool(int(config_values.split('|')[8])),
'season_all_banner': bool(int(config_values.split('|')[9])),
'enable': bool(int(config_values.split('|')[10])),
})
self.save()
# rename old config
os.rename(filename, f'{filename}.migrated')
# rename old config private key
if os.path.exists(private_key_filename):
os.rename(private_key_filename, f'{private_key_filename}.migrated')
sickrage.app.log.info("Migrating config file to database was successful!")
def _get_config_file_value(self, config_object, section, key, default=None, field_type=None):
if not field_type:
field_type = str
if default is None:
default = field_type() if field_type is not str.upper else str()
if section in config_object:
section_object = config_object.get(section)
if key in section_object:
try:
value = self.convert_value(section_object.get(key), field_type)
return value or default
except Exception:
return default
return default
def convert_value(self, value, field_type):
if not field_type:
field_type = str
if value == 'None':
return ''
if field_type == bool:
return arg_to_bool(value)
return field_type(value)
def to_json(self):
return {
'general': GeneralSchema().dump(self.general),
'gui': GUISchema().dump(self.gui),
'blackhole': BlackholeSchema().dump(self.blackhole),
'sabnzbd': SABnzbdSchema().dump(self.sabnzbd),
'nzbget': NZBgetSchema().dump(self.nzbget),
'synology': SynologySchema().dump(self.synology),
'torrent': TorrentSchema().dump(self.torrent),
'kodi': KodiSchema().dump(self.kodi),
'plex': PlexSchema().dump(self.plex),
'emby': EmbySchema().dump(self.emby),
'growl': GrowlSchema().dump(self.growl),
'freemobile': FreeMobileSchema().dump(self.freemobile),
'telegram': TelegramSchema().dump(self.telegram),
'join': JoinSchema().dump(self.join_app),
'prowl': ProwlSchema().dump(self.prowl),
'twitter': TwitterSchema().dump(self.twitter),
'twilio': TwilioSchema().dump(self.twilio),
'boxcar2': Boxcar2Schema().dump(self.boxcar2),
'pushover': PushoverSchema().dump(self.pushover),
'libnotify': LibnotifySchema().dump(self.libnotify),
'nmj': NMJSchema().dump(self.nmj),
'nmjv2': NMJv2Schema().dump(self.nmjv2),
'slack': SlackSchema().dump(self.slack),
'discord': DiscordSchema().dump(self.discord),
'trakt': TraktSchema().dump(self.trakt),
'pytivo': PyTivoSchema().dump(self.pytivo),
'nma': NMASchema().dump(self.nma),
'pushalot': PushalotSchema().dump(self.pushalot),
'pushbullet': PushbulletSchema().dump(self.pushbullet),
'email': EmailSchema().dump(self.email),
'alexa': AlexaSchema().dump(self.alexa),
'subtitles': SubtitlesSchema().dump(self.subtitles),
'failedDownloads': FailedDownloadsSchema().dump(self.failed_downloads),
'failedSnatches': FailedSnatchesSchema().dump(self.failed_snatches),
'anidb': AniDBSchema().dump(self.anidb),
'qualitySizes': QualitySizesSchema().dump(self.db.session().query(self.db.QualitySizes), many=True),
'searchProvidersTorrent': SearchProvidersTorrentSchema().dump(self.db.session().query(self.db.SearchProvidersTorrent), many=True),
'searchProvidersNzb': SearchProvidersNzbSchema().dump(self.db.session().query(self.db.SearchProvidersNzb), many=True),
'searchProvidersTorrentRss': SearchProvidersTorrentRssSchema().dump(self.db.session().query(self.db.SearchProvidersTorrentRss), many=True),
'searchProvidersNewznab': SearchProvidersNewznabSchema().dump(self.db.session().query(self.db.SearchProvidersNewznab), many=True),
'metadataProviders': MetadataProvidersSchema().dump(self.db.session().query(self.db.MetadataProviders), many=True),
}
================================================
FILE: sickrage/core/config/helpers.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import base64
import datetime
import gettext
import io
import os
import re
import sys
import uuid
from itertools import cycle
import rarfile
from configobj import ConfigObj
import sickrage
from sickrage.core.helpers import encryption, move_file, extract_zipfile, make_dir
from sickrage.core.websession import WebSession
def encrypt_config(config_obj, private_key, public_key):
config_tmp_file = config_obj.filename + '.tmp'
# encrypt config
with io.BytesIO() as buffer, open(config_tmp_file, 'wb') as fd:
config_obj.write(buffer)
buffer.seek(0)
fd.write(encryption.encrypt_string(buffer.read(), public_key))
try:
decrypt_config(config_tmp_file, private_key)
sickrage.app.log.debug("Saved encrypted config to disk")
move_file(config_tmp_file, config_obj.filename)
return True
except Exception as e:
sickrage.app.log.debug("Failed to save encrypted config to disk")
os.remove(config_tmp_file)
return False
def decrypt_config(config_file, private_key):
try:
with io.BytesIO() as buffer, open(config_file, 'rb') as fd:
buffer.write(encryption.decrypt_string(fd.read(), private_key))
buffer.seek(0)
config_obj = ConfigObj(buffer, encoding='utf8')
except (AttributeError, ValueError):
# old encryption from python 2
config_obj = ConfigObj(config_file, encoding='utf8')
config_obj.walk(legacy_decrypt,
encryption_version=int(config_obj.get('General', {}).get('encryption_version', 0)),
encryption_secret=config_obj.get('General', {}).get('encryption_secret', ''),
raise_errors=False)
return config_obj
def legacy_encrypt(section, key, encryption_version, encryption_secret, _decrypt=False):
"""
:rtype: basestring
"""
# DO NOT ENCRYPT THESE
if key in ['config_version', 'encryption_version', 'encryption_secret']:
return
try:
if encryption_version == 1:
unique_key1 = hex(uuid.getnode() ** 2)
if _decrypt:
section[key] = ''.join(chr(ord(x) ^ ord(y)) for (x, y) in zip(base64.decodestring(section[key]), cycle(unique_key1)))
else:
section[key] = base64.encodestring(''.join(chr(ord(x) ^ ord(y)) for (x, y) in zip(section[key], cycle(unique_key1)))).strip()
elif encryption_version == 2:
if _decrypt:
section[key] = ''.join(chr(x ^ y) for x, y in zip(base64.b64decode(section[key]), cycle(map(ord, encryption_secret))))
else:
section[key] = base64.b64encode(''.join(chr(x ^ y) for (x, y) in zip(map(ord, section[key]), cycle(
map(ord, encryption_secret)))).encode()).decode().strip()
except Exception:
pass
def legacy_decrypt(section, key, encryption_version, encryption_secret):
legacy_encrypt(section, key, encryption_version=encryption_version, encryption_secret=encryption_secret, _decrypt=True)
def change_gui_lang(language):
mo_file = os.path.join(sickrage.LOCALE_DIR, language, "LC_MESSAGES", "messages.mo")
if language and os.path.exists(mo_file):
# Selected language
gt = gettext.translation('messages', sickrage.LOCALE_DIR, languages=[language], codeset='UTF-8')
gt.install(names=["ngettext"])
else:
# System default language
gettext.install('messages', sickrage.LOCALE_DIR, names=["ngettext"])
sickrage.app.config.gui.gui_lang = language
def change_unrar_tool(unrar_tool):
# Check for failed unrar attempt, and remove it
# Must be done before unrar is ever called or the self-extractor opens and locks startup
bad_unrar = os.path.join(sickrage.app.data_dir, 'unrar.exe')
if os.path.exists(bad_unrar) and os.path.getsize(bad_unrar) == 447440:
try:
os.remove(bad_unrar)
except OSError as e:
sickrage.app.log.warning("Unable to delete bad unrar.exe file {}: {}. You should delete it manually".format(bad_unrar, e.strerror))
for check in [unrar_tool, 'unrar']:
try:
rarfile.custom_check([check], True)
sickrage.app.unrar_tool = rarfile.UNRAR_TOOL = check
return True
except (rarfile.RarCannotExec, rarfile.RarExecError, OSError, IOError):
continue
if sys.platform == 'win32':
# Look for WinRAR installations
winrar_path = 'WinRAR\\UnRAR.exe'
# Make a set of unique paths to check from existing environment variables
check_locations = {
os.path.join(location, winrar_path) for location in (
os.environ.get("ProgramW6432"), os.environ.get("ProgramFiles(x86)"),
os.environ.get("ProgramFiles"), re.sub(r'\s?\(x86\)', '', os.environ["ProgramFiles"])
) if location
}
check_locations.add(os.path.join(sickrage.PROG_DIR, 'unrar\\unrar.exe'))
for check in check_locations:
if os.path.isfile(check):
# Can use it?
try:
rarfile.custom_check([check], True)
sickrage.app.unrar_tool = rarfile.UNRAR_TOOL = check
return True
except (rarfile.RarCannotExec, rarfile.RarExecError, OSError, IOError):
continue
# Download
sickrage.app.log.info('Trying to download unrar.exe and set the path')
unrar_zip = os.path.join(sickrage.app.data_dir, 'unrar_win.zip')
if WebSession().download("https://sickrage.ca/downloads/unrar_win.zip", filename=unrar_zip) and extract_zipfile(archive=unrar_zip,
targetDir=sickrage.app.data_dir):
try:
os.remove(unrar_zip)
except OSError as e:
sickrage.app.log.info("Unable to delete downloaded file {}: {}. You may delete it manually".format(unrar_zip, e.strerror))
check = os.path.join(sickrage.app.data_dir, "unrar.exe")
try:
rarfile.custom_check([check], True)
sickrage.app.unrar_tool = rarfile.UNRAR_TOOL = check
sickrage.app.log.info('Successfully downloaded unrar.exe and set as unrar tool')
return True
except (rarfile.RarCannotExec, rarfile.RarExecError, OSError, IOError):
sickrage.app.log.info('Sorry, unrar was not set up correctly. Try installing WinRAR and '
'make sure it is on the system PATH')
else:
sickrage.app.log.info('Unable to download unrar.exe')
if sickrage.app.config.general.unpack:
sickrage.app.log.info('Disabling UNPACK setting because no unrar is installed.')
sickrage.app.config.general.unpack = False
def change_nzb_dir(nzb_dir):
"""
Change NZB blackhole directory
:param nzb_dir: New NZB Folder location
:return: True on success, False on failure
"""
if nzb_dir == '':
sickrage.app.config.blackhole.nzb_dir = ''
return True
if os.path.normpath(sickrage.app.config.blackhole.nzb_dir) != os.path.normpath(nzb_dir):
if make_dir(nzb_dir):
sickrage.app.config.blackhole.nzb_dir = os.path.normpath(nzb_dir)
sickrage.app.log.info("Changed NZB folder to " + nzb_dir)
else:
return False
return True
def change_torrent_dir(torrent_dir):
"""
Change Torrent blackhole directory
:param torrent_dir: New torrent directory
:return: True on success, False on failure
"""
if torrent_dir == '':
sickrage.app.config.blackhole.torrent_dir = ''
return True
if os.path.normpath(sickrage.app.config.blackhole.torrent_dir) != os.path.normpath(torrent_dir):
if make_dir(torrent_dir):
sickrage.app.config.blackhole.torrent_dir = os.path.normpath(torrent_dir)
sickrage.app.log.info("Changed torrent folder to " + torrent_dir)
else:
return False
return True
def change_tv_download_dir(tv_download_dir):
"""
Change TV_DOWNLOAD directory (used by postprocessor)
:param tv_download_dir: New tv download directory
:return: True on success, False on failure
"""
if tv_download_dir == '':
sickrage.app.config.general.tv_download_dir = ''
return True
if os.path.normpath(sickrage.app.config.general.tv_download_dir) != os.path.normpath(tv_download_dir):
if make_dir(tv_download_dir):
sickrage.app.config.general.tv_download_dir = os.path.normpath(tv_download_dir)
sickrage.app.log.info("Changed TV download folder to " + tv_download_dir)
else:
return False
return True
def change_auto_postprocessor_freq(freq):
"""
Change frequency of automatic postprocessing thread
TODO: Make all thread frequency changers in config.py return True/False status
:param freq: New frequency
"""
sickrage.app.config.general.auto_postprocessor_freq = int(freq)
if sickrage.app.config.general.auto_postprocessor_freq < sickrage.app.min_auto_postprocessor_freq:
sickrage.app.config.general.auto_postprocessor_freq = sickrage.app.min_auto_postprocessor_freq
sickrage.app.scheduler.reschedule_job(sickrage.app.auto_postprocessor.name, trigger='interval',
minutes=sickrage.app.config.general.auto_postprocessor_freq)
def change_daily_searcher_freq(freq):
"""
Change frequency of daily search thread
:param freq: New frequency
"""
sickrage.app.config.general.daily_searcher_freq = int(freq)
if sickrage.app.config.general.daily_searcher_freq < sickrage.app.min_daily_searcher_freq:
sickrage.app.config.general.daily_searcher_freq = sickrage.app.min_daily_searcher_freq
sickrage.app.scheduler.reschedule_job(sickrage.app.daily_searcher.name, trigger='interval', minutes=sickrage.app.config.general.daily_searcher_freq)
def change_backlog_searcher_freq(freq):
"""
Change frequency of backlog thread
:param freq: New frequency
"""
sickrage.app.config.general.backlog_searcher_freq = int(freq)
if sickrage.app.config.general.backlog_searcher_freq < sickrage.app.min_backlog_searcher_freq:
sickrage.app.config.general.backlog_searcher_freq = sickrage.app.min_backlog_searcher_freq
sickrage.app.scheduler.reschedule_job(sickrage.app.backlog_searcher.name, trigger='interval', minutes=sickrage.app.config.general.backlog_searcher_freq)
def change_show_update_hour(freq):
"""
Change frequency of show updater thread
:param freq: New frequency
"""
sickrage.app.config.general.show_update_hour = int(freq)
if sickrage.app.config.general.show_update_hour < 0 or sickrage.app.config.general.show_update_hour > 23:
sickrage.app.config.general.show_update_hour = 0
sickrage.app.scheduler.reschedule_job(sickrage.app.show_updater.name, trigger='interval', hours=1,
start_date=datetime.datetime.utcnow().replace(hour=sickrage.app.config.general.show_update_hour))
def change_subtitle_searcher_freq(freq):
"""
Change frequency of subtitle thread
:param freq: New frequency
"""
sickrage.app.config.general.subtitle_searcher_freq = int(freq)
if sickrage.app.config.general.subtitle_searcher_freq < sickrage.app.min_subtitle_searcher_freq:
sickrage.app.config.general.subtitle_searcher_freq = sickrage.app.min_subtitle_searcher_freq
sickrage.app.scheduler.reschedule_job(sickrage.app.subtitle_searcher.name, trigger='interval', hours=sickrage.app.config.general.subtitle_searcher_freq)
def change_failed_snatch_age(age):
"""
Change age of failed snatches
:param age: New age
"""
sickrage.app.config.failed_snatches.age = int(age)
if sickrage.app.config.failed_snatches.age < sickrage.app.min_failed_snatch_age:
sickrage.app.config.failed_snatches.age = sickrage.app.min_failed_snatch_age
def change_version_notify(version_notify):
"""
Change frequency of versioncheck thread
:param version_notify: New frequency
"""
sickrage.app.config.general.version_notify = version_notify
if not sickrage.app.config.general.version_notify:
sickrage.app.latest_version_string = None
def change_web_external_port(web_external_port):
"""
Change web external port number
:param web_external_port: New web external port number
"""
if sickrage.app.config.general.enable_upnp:
sickrage.app.upnp_client.delete_nat_portmap()
sickrage.app.config.general.web_external_port = int(web_external_port)
sickrage.app.upnp_client.add_nat_portmap()
def change_auto_backup_freq(freq):
"""
Change frequency of auto-backup thread
:param freq: New frequency
"""
sickrage.app.config.general.auto_backup_freq = int(freq)
if sickrage.app.config.general.auto_backup_freq < 1:
sickrage.app.config.general.auto_backup_freq = 1
sickrage.app.scheduler.reschedule_job(sickrage.app.auto_backup.name, trigger='interval', hours=sickrage.app.config.general.auto_backup_freq)
================================================
FILE: sickrage/core/databases/__init__.py
================================================
# Author: echel0n
# URL: https://sickrage.ca
#
# This file is part of SiCKRAGE.
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
import datetime
import os
import pickle
import random
import sqlite3
import threading
from time import sleep
import alembic.command
import alembic.config
import alembic.script
import sqlalchemy
from alembic.runtime.migration import MigrationContext
from alembic.script import ScriptDirectory
from cleverdict import CleverDict
from sqlalchemy import create_engine, event, inspect, MetaData, Index, TypeDecorator
from sqlalchemy.engine import Engine, reflection, Row
from sqlalchemy.exc import OperationalError
from sqlalchemy.ext.automap import automap_base
from sqlalchemy.ext.serializer import loads, dumps
from sqlalchemy.orm import sessionmaker, mapper, scoped_session
from sqlalchemy.sql.ddl import CreateTable, CreateIndex
import sickrage
@event.listens_for(Engine, "connect")
def set_sqlite_pragma(dbapi_connection, connection_record):
if not isinstance(dbapi_connection, sqlite3.Connection):
return
old_isolation = dbapi_connection.isolation_level
dbapi_connection.isolation_level = None
cursor = dbapi_connection.cursor()
cursor.execute("PRAGMA journal_mode=WAL")
cursor.close()
dbapi_connection.isolation_level = old_isolation
@event.listens_for(mapper, "init")
def instant_defaults_listener(target, args, kwargs):
for key, column in inspect(target.__class__).columns.items():
if column.default is not None:
if callable(column.default.arg):
setattr(target, key, column.default.arg(target))
else:
setattr(target, key, column.default.arg)
class IntFlag(TypeDecorator):
impl = sqlalchemy.types.Integer()
cache_ok = True
def __init__(self, enum):
self.enum = enum
def process_bind_param(self, value, dialect):
return int(value) if value is not None else None
def process_result_value(self, value, dialect):
return self.enum(value) if value is not None else None
class ContextSession(sqlalchemy.orm.Session):
""":class:`sqlalchemy.orm.Session` which can be used as context manager"""
def __init__(self, *args, **kwargs):
super(ContextSession, self).__init__(*args, **kwargs)
self._lock = threading.RLock()
self.max_attempts = 50
def commit(self, close=False):
statement = None
params = None
for i in range(self.max_attempts):
try:
if statement and params:
self.bind.execute(statement, params)
super(ContextSession, self).commit()
except OperationalError as e:
self.rollback()
if 'database is locked' not in str(e):
raise
statement = e.statement
params = e.params
timer = random.randint(10, 30)
sickrage.app.log.debug('Retrying database commit in {}s, attempt {}'.format(timer, i))
sleep(timer)
except Exception as e:
self.rollback()
raise
else:
break
finally:
if close:
self.close()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
class SRDatabaseBase(object):
def as_dict(self):
return {c.key: getattr(self, c.key) for c in inspect(self).mapper.column_attrs}
def as_attrdict(self):
return CleverDict(self.as_dict())
def update(self, **kwargs):
primary_keys = [pk.name for pk in self.__table__.primary_key]
for key, value in kwargs.items():
if key not in primary_keys:
setattr(self, key, value)
class SRDatabase(object):
def __init__(self, name, db_type='sqlite', db_prefix='sickrage', db_host='localhost', db_port='3306', db_username='sickrage', db_password='sickrage'):
self.name = name
self.db_type = db_type
self.db_prefix = db_prefix
self.db_host = db_host
self.db_port = db_port
self.db_username = db_username
self.db_password = db_password
self.db_path = os.path.join(sickrage.app.data_dir, '{}.db'.format(self.name))
self.db_migrations_path = os.path.join(os.path.dirname(__file__), self.name, 'migrations')
self.session = scoped_session(sessionmaker(class_=ContextSession, bind=self.engine))
@property
def engine(self):
if self.db_type == 'mysql':
mysql_engine = create_engine('mysql+pymysql://{}:{}@{}:{}/'.format(self.db_username, self.db_password, self.db_host, self.db_port), echo=False)
mysql_engine.execute(f"CREATE DATABASE IF NOT EXISTS {self.db_prefix}_{self.name}")
return create_engine(
'mysql+pymysql://{}:{}@{}:{}/{}_{}'.format(self.db_username, self.db_password, self.db_host, self.db_port, self.db_prefix, self.name),
echo=False)
else:
return create_engine('sqlite:///{}'.format(self.db_path), echo=False, connect_args={'check_same_thread': False, 'timeout': 30})
@property
def version(self):
with self.engine.connect() as connection:
context = MigrationContext.configure(connection)
current_rev = context.get_current_revision()
return current_rev
def setup(self):
if inspect(self.engine).has_table('migrate_version'):
migrate_version = self.engine.execute("select version from migrate_version").fetchone().version
alembic.command.stamp(self.get_alembic_config(), str(migrate_version))
self.engine.execute("drop table migrate_version")
if not inspect(self.engine).has_table('alembic_version'):
alembic.command.stamp(self.get_alembic_config(), 'head')
sickrage.app.log.info("Performing initialization on {} database".format(self.name))
self.initialize()
# perform integrity check
sickrage.app.log.info("Performing integrity check on {} database".format(self.name))
self.integrity_check()
# upgrade database
sickrage.app.log.info("Performing upgrades on {} database".format(self.name))
self.upgrade()
# cleanup
sickrage.app.log.info("Performing cleanup on {} database".format(self.name))
self.cleanup()
# free up space
sickrage.app.log.info("Performing vacuum on {} database".format(self.name))
self.vacuum()
def initialize(self):
pass
def upgrade(self):
db_version = int(self.version)
alembic_version = int(ScriptDirectory.from_config(self.get_alembic_config()).get_current_head())
backup_filename = os.path.join(sickrage.app.data_dir, f'{self.name}_db_backup_{datetime.datetime.now().strftime("%Y%m%d_%H%M%S")}.json')
if db_version < alembic_version:
# temp code to resolve a migration bug introduced from v10.0.0, fixed in v10.0.2+
if db_version < 21 and self.name == 'main':
if inspect(self.engine).has_table('indexer_mapping') and inspect(self.engine).has_table('series_provider_mapping'):
sickrage.app.log.debug('Found offending series_provider_mapping table, removing!')
metadata = MetaData(self.engine, reflect=True)
table = metadata.tables.get('series_provider_mapping')
table.drop(self.engine)
sickrage.app.log.info(f'Backing up {self.name} database v{db_version}')
self.backup(backup_filename)
sickrage.app.log.info(f'Upgrading {self.name} database to v{alembic_version}')
alembic.command.upgrade(self.get_alembic_config(), 'head')
def get_alembic_config(self):
config = alembic.config.Config()
config.set_main_option('script_location', self.db_migrations_path)
config.set_main_option('sqlalchemy.url', str(self.engine.url))
config.set_main_option('url', str(self.engine.url))
return config
def get_metadata(self):
metadata_obj = MetaData(bind=self.engine)
metadata_obj.reflect()
return metadata_obj
def get_base(self):
base = automap_base(metadata=self.get_metadata())
base.prepare()
return base
def integrity_check(self):
if self.db_type == 'sqlite':
if self.session().scalar("PRAGMA integrity_check") != "ok":
sickrage.app.log.fatal(
f"{self.name.capitalize()} database file {self.db_path} is damaged, please restore a backup or delete the database file and restart SiCKRAGE")
def cleanup(self):
pass
def vacuum(self):
self.engine.execute("VACUUM")
def backup(self, filename):
meta = self.get_metadata()
backup_dict = {
'schema': {},
'indexes': {},
'data': {},
'version': self.version
}
for table_name, table_object in meta.tables.items():
sickrage.app.log.info(f'Backing up {self.name} database table {table_name} schema')
backup_dict['indexes'].update({table_name: []})
backup_dict['schema'].update({table_name: str(CreateTable(table_object))})
backup_dict['data'].update({table_name: dumps(self.session().query(table_object).all(), protocol=pickle.DEFAULT_PROTOCOL)})
for index in reflection.Inspector.from_engine(self.engine).get_indexes(table_name):
cols = [table_object.c[col] for col in index['column_names']]
idx = Index(index['name'], *cols)
backup_dict['indexes'][table_name].append(str(CreateIndex(idx)))
with open(filename, 'wb') as fh:
pickle.dump(backup_dict, fh, protocol=pickle.DEFAULT_PROTOCOL)
def restore(self, filename):
session = self.session()
with open(filename, 'rb') as fh:
backup_dict = pickle.load(fh)
backup_version = int(backup_dict['version'])
restore_version_matrix = {
'main': 23,
'cache': 11,
'config': 6
}
if not backup_version >= restore_version_matrix[self.name]:
sickrage.app.log.warning(f'Backup v{backup_version} for {self.name} database cannot be restored, needs to be restored with an '
f'older copy of SiCKRAGE.')
return
# drop all tables
self.get_base().metadata.drop_all()
# restore schema
if backup_dict.get('schema', None):
for table_name, schema in backup_dict['schema'].items():
sickrage.app.log.info(f'Restoring {self.name} database table {table_name} schema')
session.execute(schema)
session.commit()
# restore indexes
if backup_dict.get('indexes', None):
for table_name, indexes in backup_dict['indexes'].items():
sickrage.app.log.info(f'Restoring {self.name} database table {table_name} indexes')
for index in indexes:
session.execute(index)
session.commit()
# restore data
if backup_dict.get('data', None):
base = self.get_base()
meta = self.get_metadata()
for table_name, data in backup_dict['data'].items():
sickrage.app.log.info(f'Restoring {self.name} database table {table_name} data')
table = base.classes[table_name]
session.query(table).delete()
rows = []
for row in loads(data, meta, session):
if isinstance(row, Row):
rows.append(row._asdict())
session.bulk_insert_mappings(table, rows)
session.commit()
def shutdown(self):
self.session.close()
================================================
FILE: sickrage/core/databases/cache/__init__.py
================================================
# Author: echel0n
# URL: https://sickrage.ca
#
# This file is part of SiCKRAGE.
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
from sqlalchemy import Column, Integer, Text, String, Boolean, MetaData, Enum
from sqlalchemy.ext.declarative import declarative_base
from sickrage.core.databases import SRDatabase, SRDatabaseBase
from sickrage.core.enums import SeriesProviderID
class CacheDB(SRDatabase):
base = declarative_base(cls=SRDatabaseBase)
def __init__(self, db_type, db_prefix, db_host, db_port, db_username, db_password):
super(CacheDB, self).__init__('cache', db_type, db_prefix, db_host, db_port, db_username, db_password)
def initialize(self):
self.base.metadata.create_all(self.engine)
def cleanup(self):
def remove_duplicates_from_last_search_table():
found = []
session = self.session()
for x in session.query(CacheDB.LastSearch).all():
if x.provider in found:
x.delete()
session.commit()
else:
found.append(x.provider)
def remove_duplicates_from_scene_name_table():
found = []
session = self.session()
for x in session.query(CacheDB.SceneName).all():
if (x.series_id, x.name) in found:
x.delete()
session.commit()
else:
found.append((x.series_id, x.name))
remove_duplicates_from_last_search_table()
# remove_duplicates_from_scene_name_table()
class LastUpdate(base):
__tablename__ = 'last_update'
provider = Column(String(32), primary_key=True)
time = Column(Integer)
class LastSearch(base):
__tablename__ = 'last_search'
provider = Column(String(32), primary_key=True)
time = Column(Integer)
class SceneName(base):
__tablename__ = 'scene_names'
id = Column(Integer, primary_key=True)
series_id = Column(Integer)
name = Column(Text)
class NetworkTimezone(base):
__tablename__ = 'network_timezones'
network_name = Column(String(256), primary_key=True)
timezone = Column(Text)
class Provider(base):
__tablename__ = 'providers'
id = Column(Integer, primary_key=True)
provider = Column(Text)
name = Column(Text)
season = Column(Integer)
episodes = Column(Text)
series_id = Column(Integer)
series_provider_id = Column(Enum(SeriesProviderID))
url = Column(String(256), index=True, unique=True)
time = Column(Integer)
quality = Column(Integer)
release_group = Column(Text)
version = Column(Integer, default=-1)
seeders = Column(Integer)
leechers = Column(Integer)
size = Column(Integer)
class Announcements(base):
__tablename__ = 'announcements'
id = Column(Integer, primary_key=True)
hash = Column(String(255), unique=True, nullable=False)
seen = Column(Boolean, default=False)
================================================
FILE: sickrage/core/databases/cache/migrations/env.py
================================================
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
# fileConfig(config.config_file_name)
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = None
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection, target_metadata=target_metadata
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
================================================
FILE: sickrage/core/databases/cache/migrations/script.py.mako
================================================
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
def upgrade():
${upgrades if upgrades else "pass"}
def downgrade():
${downgrades if downgrades else "pass"}
================================================
FILE: sickrage/core/databases/cache/migrations/versions/001_Add_Initial_Tables.py
================================================
"""Initial migration
Revision ID: 1
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '1'
down_revision = None
def upgrade():
pass
def downgrade():
pass
================================================
FILE: sickrage/core/databases/cache/migrations/versions/002_Remove_ID_Column_From_LastSearch_Table.py
================================================
"""Initial migration
Revision ID: 2
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '2'
down_revision = '1'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
last_search = sa.Table('last_search', meta, autoload=True)
conn.execute(last_search.delete())
last_search.c.provider.alter(type=sa.String(32))
primary_key = sa.PrimaryKeyConstraint(last_search.c.provider)
primary_key.create()
last_search.c.id.drop()
def downgrade():
pass
================================================
FILE: sickrage/core/databases/cache/migrations/versions/003_Rename_IndexerID_To_SeriesID_On_Provider_Table.py
================================================
"""Initial migration
Revision ID: 3
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '3'
down_revision = '2'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
providers = sa.Table('providers', meta, autoload=True)
if hasattr(providers.c, 'indexer_id'):
providers.c.indexer_id.alter(name='series_id')
def downgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
providers = sa.Table('providers', meta, autoload=True)
if hasattr(providers.c, 'series_id'):
providers.c.series_id.alter(name='indexer_id')
================================================
FILE: sickrage/core/databases/cache/migrations/versions/004_Add_OAuth2Token_Table.py
================================================
"""Initial migration
Revision ID: 4
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import json
import os
from json import JSONDecodeError
import sqlalchemy as sa
from alembic import op
import sickrage
# revision identifiers, used by Alembic.
revision = '4'
down_revision = '3'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
op.create_table(
'oauth2_token',
sa.Column('id', sa.Integer, primary_key=True),
sa.Column('access_token', sa.String(255), unique=True, nullable=False),
sa.Column('refresh_token', sa.String(255), index=True),
sa.Column('expires_in', sa.Integer, nullable=False, default=0),
sa.Column('expires_at', sa.Integer, nullable=False, default=0),
sa.Column('scope', sa.Text, default=""),
sa.Column('session_state', sa.Text, default=""),
sa.Column('token_type', sa.Text, default="bearer"),
)
oauth2_token = sa.Table('oauth2_token', meta, autoload=True)
token_file = os.path.abspath(os.path.join(sickrage.app.data_dir, 'token.json'))
if os.path.exists(token_file):
with open(token_file, 'r') as fd:
try:
token = json.load(fd)
conn.execute(oauth2_token.insert().values(
access_token=token['access_token'],
refresh_token=token['refresh_token'],
expires_in=token['expires_in'],
expires_at=token['expires_at'],
scope=' '.join(token['scope']) if isinstance(token['scope'], list) else token['scope']
))
except JSONDecodeError:
pass
os.remove(token_file)
def downgrade():
# Operations to reverse the above upgrade go here.
pass
================================================
FILE: sickrage/core/databases/cache/migrations/versions/005_Add_Announcements_Table.py
================================================
"""Initial migration
Revision ID: 5
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '5'
down_revision = '4'
def upgrade():
op.create_table(
'announcements',
sa.Column('id', sa.Integer, primary_key=True),
sa.Column('hash', sa.String(255), unique=True, nullable=False),
sa.Column('seen', sa.Boolean)
)
def downgrade():
pass
================================================
FILE: sickrage/core/databases/cache/migrations/versions/006_Add_Session_State_Column_To_OAuth2Token_Table.py
================================================
"""Initial migration
Revision ID: 6
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '6'
down_revision = '5'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
oauth2_token = sa.Table('oauth2_token', meta, autoload=True)
if not hasattr(oauth2_token.c, 'session_state'):
op.add_column('oauth2_token', sa.Column('session_state', sa.Text, default=''))
def downgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
oauth2_token = sa.Table('oauth2_token', meta, autoload=True)
if hasattr(oauth2_token.c, 'session_state'):
op.drop_column('oauth2_token', 'session_state')
================================================
FILE: sickrage/core/databases/cache/migrations/versions/007_Add_Token_Type_Column_To_OAuth2Token_Table.py
================================================
"""Initial migration
Revision ID: 7
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '7'
down_revision = '6'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
oauth2_token = sa.Table('oauth2_token', meta, autoload=True)
if not hasattr(oauth2_token.c, 'token_type'):
op.add_column('oauth2_token', sa.Column('token_type', sa.Text, default='bearer'))
def downgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
oauth2_token = sa.Table('oauth2_token', meta, autoload=True)
if hasattr(oauth2_token.c, 'token_type'):
op.drop_column('oauth2_token', 'token_type')
================================================
FILE: sickrage/core/databases/cache/migrations/versions/008_Drop_QuickSearch_Tables.py
================================================
"""Initial migration
Revision ID: 8
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
from sqlalchemy import inspect
revision = '8'
down_revision = '7'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
if inspect(conn).has_table('quicksearch_shows'):
op.drop_table('quicksearch_shows')
if inspect(conn).has_table('quicksearch_episodes'):
op.drop_table('quicksearch_episodes')
def downgrade():
pass
================================================
FILE: sickrage/core/databases/cache/migrations/versions/009_Add_SeriesProviderID_Column_To_Providers_Table.py
================================================
"""Initial migration
Revision ID: 7
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
from sickrage.core.enums import SeriesProviderID
revision = '9'
down_revision = '8'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
providers = sa.Table('providers', meta, autoload=True)
op.add_column('providers', sa.Column('series_provider_id', sa.Enum, default=SeriesProviderID.THETVDB))
with op.get_context().begin_transaction():
for row in conn.execute(providers.select()):
conn.execute(f'UPDATE providers SET series_provider_id = "{SeriesProviderID.THETVDB.name}" WHERE providers.id = {row.id}')
def downgrade():
pass
================================================
FILE: sickrage/core/databases/cache/migrations/versions/010_Remove_OAuth2Token_Table.py
================================================
"""Initial migration
Revision ID: 10
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import json
import os
from json import JSONDecodeError
import sqlalchemy as sa
from alembic import op
from keycloak.exceptions import KeycloakClientError
from sqlalchemy import orm, inspect
import sickrage
# revision identifiers, used by Alembic.
from sickrage.core import ConfigDB
revision = '10'
down_revision = '9'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
oauth2_token = sa.Table('oauth2_token', meta, autoload=True)
refresh_token = None
with op.get_context().begin_transaction():
for row in conn.execute(oauth2_token.select()):
refresh_token = row.refresh_token
if refresh_token:
break
try:
if refresh_token:
certs = sickrage.app.auth_server.certs()
if certs:
new_token = sickrage.app.auth_server.refresh_token(refresh_token)
if new_token:
decoded_token = sickrage.app.auth_server.decode_token(new_token['access_token'], certs)
apikey = decoded_token.get('apikey')
if apikey:
session = sickrage.app.config.db.session()
general = session.query(ConfigDB.General).one()
general.sso_api_key = apikey
session.commit()
except (KeycloakClientError, orm.exc.NoResultFound):
pass
if inspect(conn).has_table('oauth2_token'):
op.drop_table('oauth2_token')
def downgrade():
# Operations to reverse the above upgrade go here.
pass
================================================
FILE: sickrage/core/databases/cache/migrations/versions/011_Bump_Version.py
================================================
"""Initial migration
Revision ID: 11
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import json
import os
from json import JSONDecodeError
import sqlalchemy as sa
from alembic import op
from keycloak.exceptions import KeycloakClientError
from sqlalchemy import orm, inspect
import sickrage
# revision identifiers, used by Alembic.
from sickrage.core import ConfigDB
revision = '11'
down_revision = '10'
def upgrade():
pass
def downgrade():
# Operations to reverse the above upgrade go here.
pass
================================================
FILE: sickrage/core/databases/config/__init__.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import datetime
import json
import random
import six
from sqlalchemy import Column, Text, Integer, ForeignKey, Boolean, Enum, Float
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.mutable import MutableDict
from sqlalchemy_utils import JSONType
from sqlalchemy_utils.types.encrypted.encrypted_type import StringEncryptedType, DatetimeHandler
import sickrage
from sickrage.core.common import Qualities, EpisodeStatus
from sickrage.core.databases import SRDatabaseBase, SRDatabase, IntFlag
from sickrage.core.enums import DefaultHomePage, MultiEpNaming, CpuPreset, CheckPropersInterval, \
FileTimestampTimezone, ProcessMethod, NzbMethod, TorrentMethod, SearchFormat, UserPermission, PosterSortDirection, HomeLayout, PosterSortBy, \
HistoryLayout, TimezoneDisplay, UITheme, TraktAddMethod, SeriesProviderID
from sickrage.core.helpers import generate_api_key, generate_secret
from sickrage.core.tv.show.coming_episodes import ComingEpsLayout, ComingEpsSortBy
from sickrage.notification_providers.nmjv2 import NMJv2Location
from sickrage.search_providers import SearchProviderType
def encryption_key():
try:
return getattr(sickrage.app.config.user, 'sub_id', None) or 'sickrage'
except Exception:
return 'sickrage'
class CustomStringEncryptedType(StringEncryptedType):
reset = False
def process_bind_param(self, value, dialect):
"""Encrypt a value on the way in."""
if value is not None:
if not self.reset:
self._update_key()
else:
self.engine._update_key('sickrage')
try:
value = self.underlying_type.process_bind_param(
value, dialect
)
except AttributeError:
# Doesn't have 'process_bind_param'
# Handle 'boolean' and 'dates'
type_ = self.underlying_type.python_type
if issubclass(type_, bool):
value = 'true' if value else 'false'
elif issubclass(type_, (datetime.date, datetime.time)):
value = value.isoformat()
elif issubclass(type_, JSONType):
value = six.text_type(json.dumps(value))
return self.engine.encrypt(value)
def process_result_value(self, value, dialect):
"""Decrypt value on the way out."""
if value is not None:
self._update_key()
try:
decrypted_value = self.engine.decrypt(value)
except ValueError:
self.engine._update_key('sickrage')
decrypted_value = self.engine.decrypt(value)
try:
return self.underlying_type.process_result_value(
decrypted_value, dialect
)
except AttributeError:
# Doesn't have 'process_result_value'
# Handle 'boolean' and 'dates'
type_ = self.underlying_type.python_type
date_types = [datetime.datetime, datetime.time, datetime.date]
if issubclass(type_, bool):
return decrypted_value == 'true'
elif type_ in date_types:
return DatetimeHandler.process_value(
decrypted_value, type_
)
elif issubclass(type_, JSONType):
return json.loads(decrypted_value)
# Handle all others
return self.underlying_type.python_type(decrypted_value)
class ConfigDB(SRDatabase):
base = declarative_base(cls=SRDatabaseBase)
def __init__(self, db_type, db_prefix, db_host, db_port, db_username, db_password):
super(ConfigDB, self).__init__('config', db_type, db_prefix, db_host, db_port, db_username, db_password)
def initialize(self):
self.base.metadata.create_all(self.engine)
class Users(base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True, autoincrement=True)
username = Column(Text, default='', index=True, unique=True)
password = Column(Text, default='')
email = Column(Text, default='', index=True)
sub_id = Column(Text, default='')
permissions = Column(Enum(UserPermission), default=UserPermission.GUEST)
enable = Column(Boolean, default=True)
class General(base):
__tablename__ = 'general'
id = Column(Integer, primary_key=True, autoincrement=True)
server_id = Column(Text, default='')
enable_sickrage_api = Column(Boolean, default=True)
log_size = Column(Integer, default=1048576)
calendar_unprotected = Column(Boolean, default=False)
https_key = Column(Text, default='server.key')
https_cert = Column(Text, default='server.crt')
allow_high_priority = Column(Boolean, default=False)
anon_redirect = Column(Text, default='https://anonym.to/?')
series_provider_timeout = Column(Integer, default=20)
web_use_gzip = Column(Boolean, default=True)
daily_searcher_freq = Column(Integer, default=40)
ignore_words = Column(Text, default=','.join(['german', 'french', 'core2hd', 'dutch', 'swedish', 'reenc', 'MrLss']))
api_v1_key = Column(Text, default=generate_api_key())
sso_api_key = Column(Text, default='')
sso_auth_enabled = Column(Boolean, default=True)
local_auth_enabled = Column(Boolean, default=False)
ip_whitelist_enabled = Column(Boolean, default=False)
ip_whitelist_localhost_enabled = Column(Boolean, default=False)
ip_whitelist = Column(Text, default='')
proper_searcher_interval = Column(Enum(CheckPropersInterval), default=CheckPropersInterval.DAILY)
nzb_method = Column(Enum(NzbMethod), default=NzbMethod.BLACKHOLE)
web_cookie_secret = Column(Text, default=generate_secret())
ssl_verify = Column(Boolean, default=False)
enable_upnp = Column(Boolean, default=False)
version_notify = Column(Boolean, default=False)
web_root = Column(Text, default='')
web_log = Column(Text, default='')
add_shows_wo_dir = Column(Boolean, default=False)
debug = Column(Boolean, default=False)
series_provider_default = Column(Enum(SeriesProviderID), default=SeriesProviderID.THETVDB)
use_torrents = Column(Boolean, default=True)
display_all_seasons = Column(Boolean, default=True)
usenet_retention = Column(Integer, default=500)
download_propers = Column(Boolean, default=True)
pip3_path = Column(Text, default='pip3')
del_rar_contents = Column(Boolean, default=False)
process_method = Column(Enum(ProcessMethod), default=ProcessMethod.COPY)
file_timestamp_timezone = Column(Enum(FileTimestampTimezone), default=FileTimestampTimezone.NETWORK)
auto_update = Column(Boolean, default=True)
tv_download_dir = Column(Text, default='')
naming_custom_abd = Column(Boolean, default=False)
scene_default = Column(Boolean, default=False)
skip_downloaded_default = Column(Boolean, default=False)
add_show_year_default = Column(Boolean, default=False)
naming_sports_pattern = Column(Text, default='%SN - %A-D - %EN')
create_missing_show_dirs = Column(Boolean, default=False)
trash_rotate_logs = Column(Boolean, default=False)
airdate_episodes = Column(Boolean, default=False)
notify_on_update = Column(Boolean, default=True)
backup_on_update = Column(Boolean, default=True)
backlog_days = Column(Integer, default=7)
root_dirs = Column(Text, default='')
naming_pattern = Column(Text, default='Season %0S/%SN - S%0SE%0E - %EN')
sort_article = Column(Boolean, default=False)
handle_reverse_proxy = Column(Boolean, default=False)
postpone_if_sync_files = Column(Boolean, default=True)
cpu_preset = Column(Enum(CpuPreset), default=CpuPreset.NORMAL)
nfo_rename = Column(Boolean, default=True)
naming_anime_multi_ep = Column(Enum(MultiEpNaming), default=MultiEpNaming.REPEAT)
use_nzbs = Column(Boolean, default=False)
web_ipv6 = Column(Boolean, default=False)
anime_default = Column(Boolean, default=False)
default_page = Column(Enum(DefaultHomePage), default=DefaultHomePage.HOME)
version_updater_freq = Column(Integer, default=1)
download_url = Column(Text, default='')
show_update_hour = Column(Integer, default=3)
enable_rss_cache = Column(Boolean, default=True)
torrent_file_to_magnet = Column(Boolean, default=False)
torrent_magnet_to_file = Column(Boolean, default=True)
download_unverified_magnet_link = Column(Boolean, default=False)
status_default = Column(Enum(EpisodeStatus), default=EpisodeStatus.SKIPPED)
naming_anime = Column(Integer, default=3)
naming_custom_sports = Column(Boolean, default=False)
naming_custom_anime = Column(Boolean, default=False)
naming_anime_pattern = Column(Text, default='Season %0S/%SN - S%0SE%0E - %EN')
randomize_providers = Column(Boolean, default=False)
process_automatically = Column(Boolean, default=False)
git_path = Column(Text, default='git')
sync_files = Column(Text, default=','.join(['!sync', 'lftp-pget-status', 'part', 'bts', '!qb']))
web_port = Column(Integer, default=8081)
web_external_port = Column(Integer, default=random.randint(49152, 65536))
launch_browser = Column(Boolean, default=False)
unpack = Column(Boolean, default=False)
unpack_dir = Column(Text, default='')
delete_non_associated_files = Column(Boolean, default=True)
move_associated_files = Column(Boolean, default=False)
naming_multi_ep = Column(Enum(MultiEpNaming), default=MultiEpNaming.REPEAT)
random_user_agent = Column(Boolean, default=False)
torrent_method = Column(Enum(TorrentMethod), default=TorrentMethod.BLACKHOLE)
trash_remove_show = Column(Boolean, default=False)
enable_https = Column(Boolean, default=False)
no_delete = Column(Boolean, default=False)
naming_abd_pattern = Column(Text, default='%SN - %A.D - %EN')
socket_timeout = Column(Integer, default=30)
proxy_setting = Column(Text, default='')
backlog_searcher_freq = Column(Integer, default=1440)
subtitle_searcher_freq = Column(Integer, default=1)
auto_postprocessor_freq = Column(Integer, default=10)
notify_on_login = Column(Boolean, default=False)
rename_episodes = Column(Boolean, default=True)
quality_default = Column(IntFlag(Qualities), default=Qualities.SD)
extra_scripts = Column(Text, default='')
flatten_folders_default = Column(Boolean, default=False)
series_provider_default_language = Column(Text, default='eng')
show_update_stale = Column(Boolean, default=True)
ep_default_deleted_status = Column(Enum(EpisodeStatus), default=EpisodeStatus.ARCHIVED)
no_restart = Column(Boolean, default=False)
allowed_video_file_exts = Column(Text, default=','.join(['avi', 'mkv', 'mpg', 'mpeg', 'wmv', 'ogm', 'mp4', 'iso', 'img', 'divx', 'm2ts', 'm4v', 'ts',
'flv', 'f4v', 'mov', 'rmvb', 'vob', 'dvr-ms', 'wtv', 'ogv', '3gp', 'webm', 'tp']))
require_words = Column(Text, default='')
naming_strip_year = Column(Boolean, default=False)
proxy_series_providers = Column(Boolean, default=True)
log_nr = Column(Integer, default=5)
git_reset = Column(Boolean, default=True)
search_format_default = Column(Enum(SearchFormat), default=SearchFormat.STANDARD)
skip_removed_files = Column(Boolean, default=False)
status_default_after = Column(Enum(EpisodeStatus), default=EpisodeStatus.WANTED)
ignored_subs_list = Column(Text, default=','.join(['dk', 'fin', 'heb', 'kor', 'nor', 'nordic', 'pl', 'swe']))
calendar_icons = Column(Boolean, default=False)
keep_processed_dir = Column(Boolean, default=True)
processor_follow_symlinks = Column(Boolean, default=False)
allowed_extensions = Column(Text, default=','.join(['srt', 'nfo', 'srr', 'sfv']))
view_changelog = Column(Boolean, default=False)
strip_special_file_bits = Column(Boolean, default=True)
max_queue_workers = Column(Integer, default=5)
update_video_metadata = Column(Boolean, default=True)
auto_backup_enable = Column(Boolean, default=False)
auto_backup_freq = Column(Integer, default=24)
auto_backup_keep_num = Column(Integer, default=1)
auto_backup_dir = Column(Text, default='')
class GUI(base):
__tablename__ = 'gui'
id = Column(Integer, primary_key=True, autoincrement=True)
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"))
coming_eps_display_paused = Column(Boolean, default=False)
display_show_specials = Column(Boolean, default=True)
gui_lang = Column(Text, default='')
history_limit = Column(Integer, default=100)
poster_sort_dir = Column(Enum(PosterSortDirection), default=PosterSortDirection.ASCENDING)
coming_eps_missed_range = Column(Integer, default=7)
date_preset = Column(Text, default='%x')
fuzzy_dating = Column(Boolean, default=False)
fanart_background = Column(Boolean, default=True)
home_layout = Column(Enum(HomeLayout), default=HomeLayout.POSTER)
coming_eps_layout = Column(Enum(ComingEpsLayout), default=ComingEpsLayout.POSTER)
coming_eps_sort = Column(Enum(ComingEpsSortBy), default=ComingEpsSortBy.DATE)
poster_sort_by = Column(Enum(PosterSortBy), default=PosterSortBy.NAME)
time_preset = Column(Text, default='%I:%M:%S%p')
time_preset_w_seconds = Column(Text, default='')
trim_zero = Column(Boolean, default=False)
fanart_background_opacity = Column(Float, default=0.4)
history_layout = Column(Enum(HistoryLayout), default=HistoryLayout.DETAILED)
filter_row = Column(Boolean, default=False)
timezone_display = Column(Enum(TimezoneDisplay), default=TimezoneDisplay.LOCAL)
theme_name = Column(Enum(UITheme), default=UITheme.DARK)
class Blackhole(base):
__tablename__ = 'blackhole'
id = Column(Integer, primary_key=True, autoincrement=True)
nzb_dir = Column(Text, default='')
torrent_dir = Column(Text, default='')
class SABnzbd(base):
__tablename__ = 'sabnzbd'
id = Column(Integer, primary_key=True, autoincrement=True)
username = Column(Text, default='')
password = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
apikey = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
category = Column(Text, default='tv')
category_backlog = Column(Text, default='tv')
category_anime = Column(Text, default='anime')
category_anime_backlog = Column(Text, default='anime')
host = Column(Text, default='')
forced = Column(Boolean, default=False)
class NZBget(base):
__tablename__ = 'nzbget'
id = Column(Integer, primary_key=True, autoincrement=True)
username = Column(Text, default='')
password = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
category = Column(Text, default='tv')
category_backlog = Column(Text, default='tv')
category_anime = Column(Text, default='anime')
category_anime_backlog = Column(Text, default='anime')
host = Column(Text, default='')
use_https = Column(Boolean, default=False)
priority = Column(Integer, default=100)
class Synology(base):
__tablename__ = 'synology'
id = Column(Integer, primary_key=True, autoincrement=True)
username = Column(Text, default='')
password = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
host = Column(Text, default='')
path = Column(Text, default='')
enable_index = Column(Boolean, default=False)
enable_notifications = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
class Torrent(base):
__tablename__ = 'torrent'
id = Column(Integer, primary_key=True, autoincrement=True)
username = Column(Text, default='')
password = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
host = Column(Text, default='')
path = Column(Text, default='')
seed_time = Column(Integer, default=0)
paused = Column(Boolean, default=False)
high_bandwidth = Column(Boolean, default=False)
verify_cert = Column(Boolean, default=False)
label = Column(Text, default='')
label_anime = Column(Text, default='')
rpc_url = Column(Text, default='')
auth_type = Column(Text, default='')
class Kodi(base):
__tablename__ = 'kodi'
id = Column(Integer, primary_key=True, autoincrement=True)
username = Column(Text, default='')
password = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
host = Column(Text, default='')
enable = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
update_library = Column(Boolean, default=False)
update_full = Column(Boolean, default=False)
update_only_first = Column(Boolean, default=False)
always_on = Column(Boolean, default=False)
class Plex(base):
__tablename__ = 'plex'
id = Column(Integer, primary_key=True, autoincrement=True)
username = Column(Text, default='')
password = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
client_username = Column(Text, default='')
client_password = Column(Text, default='')
host = Column(Text, default='')
server_host = Column(Text, default='')
server_token = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
enable = Column(Boolean, default=False)
enable_client = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
update_library = Column(Boolean, default=False)
class Emby(base):
__tablename__ = 'emby'
id = Column(Integer, primary_key=True, autoincrement=True)
host = Column(Text, default='')
apikey = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
enable = Column(Boolean, default=False)
class Growl(base):
__tablename__ = 'growl'
id = Column(Integer, primary_key=True, autoincrement=True)
host = Column(Text, default='')
password = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
enable = Column(Boolean, default=False)
class FreeMobile(base):
__tablename__ = 'freemobile'
id = Column(Integer, primary_key=True, autoincrement=True)
user_id = Column(Text, default='')
apikey = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
enable = Column(Boolean, default=False)
class Telegram(base):
__tablename__ = 'telegram'
id = Column(Integer, primary_key=True, autoincrement=True)
user_id = Column(Text, default='')
apikey = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
enable = Column(Boolean, default=False)
class Join(base):
__tablename__ = 'join'
id = Column(Integer, primary_key=True, autoincrement=True)
user_id = Column(Text, default='')
apikey = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
enable = Column(Boolean, default=False)
class Prowl(base):
__tablename__ = 'prowl'
id = Column(Integer, primary_key=True, autoincrement=True)
apikey = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
priority = Column(Integer, default=0)
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
enable = Column(Boolean, default=False)
class Twitter(base):
__tablename__ = 'twitter'
id = Column(Integer, primary_key=True, autoincrement=True)
username = Column(Text, default='')
password = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
prefix = Column(Text, default='')
dm_to = Column(Text, default='')
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
use_dm = Column(Boolean, default=False)
enable = Column(Boolean, default=False)
class Twilio(base):
__tablename__ = 'twilio'
id = Column(Integer, primary_key=True, autoincrement=True)
phone_sid = Column(Text, default='')
account_sid = Column(Text, default='')
auth_token = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
to_number = Column(Text, default='')
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
enable = Column(Boolean, default=False)
class Boxcar2(base):
__tablename__ = 'boxcar2'
id = Column(Integer, primary_key=True, autoincrement=True)
access_token = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
enable = Column(Boolean, default=False)
class Pushover(base):
__tablename__ = 'pushover'
id = Column(Integer, primary_key=True, autoincrement=True)
user_key = Column(Text, default='')
apikey = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
device = Column(Text, default='')
sound = Column(Text, default='pushover')
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
enable = Column(Boolean, default=False)
class Libnotify(base):
__tablename__ = 'libnotify'
id = Column(Integer, primary_key=True, autoincrement=True)
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
enable = Column(Boolean, default=False)
class NMJ(base):
__tablename__ = 'nmj'
id = Column(Integer, primary_key=True, autoincrement=True)
host = Column(Text, default='')
database = Column(Text, default='')
mount = Column(Text, default='')
enable = Column(Boolean, default=False)
class NMJv2(base):
__tablename__ = 'nmjv2'
id = Column(Integer, primary_key=True, autoincrement=True)
host = Column(Text, default='')
database = Column(Text, default='')
db_loc = Column(Enum(NMJv2Location), default=NMJv2Location.LOCAL)
enable = Column(Boolean, default=False)
class Slack(base):
__tablename__ = 'slack'
id = Column(Integer, primary_key=True, autoincrement=True)
webhook = Column(Text, default='')
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
enable = Column(Boolean, default=False)
class Discord(base):
__tablename__ = 'discord'
id = Column(Integer, primary_key=True, autoincrement=True)
webhook = Column(Text, default='')
avatar_url = Column(Text, default='')
name = Column(Text, default='')
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
tts = Column(Boolean, default=False)
enable = Column(Boolean, default=False)
class Trakt(base):
__tablename__ = 'trakt'
id = Column(Integer, primary_key=True, autoincrement=True)
username = Column(Text, default='')
blacklist_name = Column(Text, default='')
oauth_token = Column(MutableDict.as_mutable(CustomStringEncryptedType(JSONType, key=encryption_key)), default={})
remove_watchlist = Column(Boolean, default=False)
remove_serieslist = Column(Boolean, default=False)
remove_show_from_sickrage = Column(Boolean, default=False)
sync_watchlist = Column(Boolean, default=False)
method_add = Column(Enum(TraktAddMethod), default=TraktAddMethod.SKIP_ALL)
start_paused = Column(Boolean, default=False)
use_recommended = Column(Boolean, default=False)
sync = Column(Boolean, default=False)
sync_remove = Column(Boolean, default=False)
series_provider_default = Column(Enum(SeriesProviderID), default=SeriesProviderID.THETVDB)
timeout = Column(Integer, default=30)
enable = Column(Boolean, default=False)
class PyTivo(base):
__tablename__ = 'pytivo'
id = Column(Integer, primary_key=True, autoincrement=True)
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
update_library = Column(Boolean, default=False)
host = Column(Text, default='')
share_name = Column(Text, default='')
tivo_name = Column(Text, default='')
enable = Column(Boolean, default=False)
class NMA(base):
__tablename__ = 'nma'
id = Column(Integer, primary_key=True, autoincrement=True)
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
api_keys = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
priority = Column(Integer, default=0)
enable = Column(Boolean, default=False)
class Pushalot(base):
__tablename__ = 'pushalot'
id = Column(Integer, primary_key=True, autoincrement=True)
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
auth_token = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
enable = Column(Boolean, default=False)
class Pushbullet(base):
__tablename__ = 'pushbullet'
id = Column(Integer, primary_key=True, autoincrement=True)
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
api_key = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
device = Column(Text, default='')
enable = Column(Boolean, default=False)
class Email(base):
__tablename__ = 'email'
id = Column(Integer, primary_key=True, autoincrement=True)
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
host = Column(Text, default='')
port = Column(Text, default='')
tls = Column(Boolean, default=False)
username = Column(Text, default='')
password = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
send_from = Column(Text, default='')
send_to_list = Column(Text, default='')
enable = Column(Boolean, default=False)
class Alexa(base):
__tablename__ = 'alexa'
id = Column(Integer, primary_key=True, autoincrement=True)
notify_on_download = Column(Boolean, default=False)
notify_on_subtitle_download = Column(Boolean, default=False)
notify_on_snatch = Column(Boolean, default=False)
enable = Column(Boolean, default=False)
class Subtitles(base):
__tablename__ = 'subtitles'
id = Column(Integer, primary_key=True, autoincrement=True)
languages = Column(Text, default='')
services_list = Column(Text, default='')
dir = Column(Text, default='')
default = Column(Boolean, default=False)
history = Column(Boolean, default=False)
hearing_impaired = Column(Boolean, default=False)
enable_embedded = Column(Boolean, default=False)
multi = Column(Boolean, default=False)
services_enabled = Column(Text, default='')
extra_scripts = Column(Text, default='')
addic7ed_user = Column(Text, default='')
addic7ed_pass = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
legendastv_user = Column(Text, default='')
legendastv_pass = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
itasa_user = Column(Text, default='')
itasa_pass = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
opensubtitles_user = Column(Text, default='')
opensubtitles_pass = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
enable = Column(Boolean, default=False)
class FailedDownloads(base):
__tablename__ = 'failed_downloads'
id = Column(Integer, primary_key=True, autoincrement=True)
enable = Column(Boolean, default=False)
class FailedSnatches(base):
__tablename__ = 'failed_snatches'
id = Column(Integer, primary_key=True, autoincrement=True)
age = Column(Integer, default=1)
enable = Column(Boolean, default=False)
class AniDB(base):
__tablename__ = 'anidb'
id = Column(Integer, primary_key=True, autoincrement=True)
username = Column(Text, default='')
password = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
use_my_list = Column(Boolean, default=False)
split_home = Column(Boolean, default=False)
enable = Column(Boolean, default=False)
class QualitySizes(base):
__tablename__ = 'quality_sizes'
id = Column(Integer, primary_key=True, autoincrement=True)
quality = Column(IntFlag(Qualities))
min_size = Column(Integer, default=0)
max_size = Column(Integer, default=0)
class SearchProvidersMixin(object):
id = Column(Integer, primary_key=True, autoincrement=True)
provider_id = Column(Text, unique=True)
sort_order = Column(Integer, default=0)
search_mode = Column(Text, default='eponly')
search_separator = Column(Text, default=' ')
cookies = Column(Text, default='')
proper_strings = Column(Text, default=','.join(['PROPER', 'REPACK', 'REAL', 'RERIP']))
private = Column(Boolean, default=False)
supports_backlog = Column(Boolean, default=True)
supports_absolute_numbering = Column(Boolean, default=False)
anime_only = Column(Boolean, default=False)
search_fallback = Column(Boolean, default=False)
enable_daily = Column(Boolean, default=True)
enable_backlog = Column(Boolean, default=True)
enable_cookies = Column(Boolean, default=False)
custom_settings = Column(MutableDict.as_mutable(CustomStringEncryptedType(JSONType, key=encryption_key)), default={})
enable = Column(Boolean, default=False)
class SearchProvidersTorrent(SearchProvidersMixin, base):
__tablename__ = 'search_providers_torrent'
provider_type = Column(Enum(SearchProviderType), default=SearchProviderType.TORRENT)
ratio = Column(Integer, default=0)
class SearchProvidersNzb(SearchProvidersMixin, base):
__tablename__ = 'search_providers_nzb'
provider_type = Column(Enum(SearchProviderType), default=SearchProviderType.NZB)
api_key = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
username = Column(Text, default='')
class SearchProvidersTorrentRss(SearchProvidersMixin, base):
__tablename__ = 'search_providers_torrent_rss'
provider_type = Column(Enum(SearchProviderType), default=SearchProviderType.TORRENT_RSS)
name = Column(Text, default='')
url = Column(Text, default='')
title_tag = Column(Text, default='')
ratio = Column(Integer, default=0)
class SearchProvidersNewznab(SearchProvidersMixin, base):
__tablename__ = 'search_providers_newznab'
provider_type = Column(Enum(SearchProviderType), default=SearchProviderType.NEWZNAB)
name = Column(Text, default='')
url = Column(Text, default='')
cat_ids = Column(Text, default='')
api_key = Column(CustomStringEncryptedType(Text, key=encryption_key), default='')
username = Column(Text, default='')
class MetadataProviders(base):
__tablename__ = 'metadata_providers'
id = Column(Integer, primary_key=True, autoincrement=True)
provider_id = Column(Text, unique=True)
show_metadata = Column(Boolean, default=False)
episode_metadata = Column(Boolean, default=False)
fanart = Column(Boolean, default=False)
poster = Column(Boolean, default=False)
banner = Column(Boolean, default=False)
episode_thumbnails = Column(Boolean, default=False)
season_posters = Column(Boolean, default=False)
season_banners = Column(Boolean, default=False)
season_all_poster = Column(Boolean, default=False)
season_all_banner = Column(Boolean, default=False)
enable = Column(Boolean, default=False)
================================================
FILE: sickrage/core/databases/config/migrations/env.py
================================================
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
# fileConfig(config.config_file_name)
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = None
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection, target_metadata=target_metadata
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
================================================
FILE: sickrage/core/databases/config/migrations/script.py.mako
================================================
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
def upgrade():
${upgrades if upgrades else "pass"}
def downgrade():
${downgrades if downgrades else "pass"}
================================================
FILE: sickrage/core/databases/config/migrations/versions/001_Add_Initial_Tables.py
================================================
"""Initial migration
Revision ID: 1
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '1'
down_revision = None
def upgrade():
pass
def downgrade():
pass
================================================
FILE: sickrage/core/databases/config/migrations/versions/002_Remove_Web_Host_Column.py
================================================
"""Initial migration
Revision ID: 1
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
from alembic import op
# revision identifiers, used by Alembic.
revision = '2'
down_revision = '1'
def upgrade():
with op.batch_alter_table('general') as batch_op:
batch_op.drop_column('web_host')
def downgrade():
pass
================================================
FILE: sickrage/core/databases/config/migrations/versions/003_Remove_Search_Providers_Newznab_Key_Column.py
================================================
"""Initial migration
Revision ID: 3
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
from alembic import op
# revision identifiers, used by Alembic.
revision = '3'
down_revision = '2'
def upgrade():
with op.batch_alter_table('search_providers_newznab') as batch_op:
batch_op.drop_column('key')
def downgrade():
pass
================================================
FILE: sickrage/core/databases/config/migrations/versions/004_Add_SSO_API_Key_Column_To_General_Table.py
================================================
"""Initial migration
Revision ID: 4
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '4'
down_revision = '3'
def upgrade():
op.add_column('general', sa.Column('sso_api_key', sa.Text, default=''))
def downgrade():
pass
================================================
FILE: sickrage/core/databases/config/migrations/versions/005_Convert_Default_Series_Provider_Language_Code_To_ISO6393_In_General_Table.py
================================================
"""Initial migration
Revision ID: 4
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import babelfish
from alembic import op
# revision identifiers, used by Alembic.
revision = '5'
down_revision = '4'
def upgrade():
conn = op.get_bind()
row = conn.execute(f"SELECT series_provider_default_language FROM general").first()
if len(row.series_provider_default_language) == 2:
lang = babelfish.Language.fromalpha2(row.series_provider_default_language)
conn.execute(f'UPDATE general SET series_provider_default_language = "{lang.alpha3}"')
def downgrade():
pass
================================================
FILE: sickrage/core/databases/config/migrations/versions/006_Bump_Version.py
================================================
"""Initial migration
Revision ID: 6
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import babelfish
from alembic import op
# revision identifiers, used by Alembic.
revision = '6'
down_revision = '5'
def upgrade():
pass
def downgrade():
pass
================================================
FILE: sickrage/core/databases/config/migrations/versions/007_Convert_NMA_Priority_Column_To_Integer.py
================================================
"""Initial migration
Revision ID: 7
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '7'
down_revision = '6'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
nma = sa.Table('nma', meta, autoload=True)
for row in conn.execute(nma.select()):
priority = row.priority
if isinstance(priority, str):
try:
priority = int(priority or 0)
except ValueError:
priority = 0
conn.execute(f'UPDATE nma SET priority = {priority} WHERE nma.id = {row.id}')
def downgrade():
pass
================================================
FILE: sickrage/core/databases/config/migrations/versions/008_Add_Update_Video_Metadata_Column_To_General_Table.py
================================================
"""Initial migration
Revision ID: 8
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '8'
down_revision = '7'
def upgrade():
op.add_column('general', sa.Column('update_video_metadata', sa.Boolean, server_default='true'))
def downgrade():
pass
================================================
FILE: sickrage/core/databases/config/migrations/versions/009_Add_AutoBackup_Columns_To_General_Table.py
================================================
"""Initial migration
Revision ID: 9
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '9'
down_revision = '8'
def upgrade():
op.add_column('general', sa.Column('auto_backup_enable', sa.Boolean))
op.add_column('general', sa.Column('auto_backup_freq', sa.Integer, server_default='24'))
op.add_column('general', sa.Column('auto_backup_keep_num', sa.Integer, server_default='1'))
op.add_column('general', sa.Column('auto_backup_dir', sa.Text, server_default=''))
def downgrade():
pass
================================================
FILE: sickrage/core/databases/config/schemas.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
from marshmallow_enum import EnumField
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema
from sickrage.core.common import Qualities, EpisodeStatus
from sickrage.core.databases.config import ConfigDB
from sickrage.core.enums import UserPermission, CheckPropersInterval, NzbMethod, ProcessMethod, FileTimestampTimezone, CpuPreset, MultiEpNaming, \
DefaultHomePage, TorrentMethod, SearchFormat, PosterSortDirection, HomeLayout, PosterSortBy, HistoryLayout, TimezoneDisplay, UITheme, \
TraktAddMethod, SeriesProviderID
from sickrage.core.helpers import camelcase
from sickrage.core.tv.show.coming_episodes import ComingEpsLayout, ComingEpsSortBy
from sickrage.notification_providers.nmjv2 import NMJv2Location
from sickrage.search_providers import SearchProviderType
class UsersSchema(SQLAlchemyAutoSchema):
permissions = EnumField(UserPermission)
class Meta:
model = ConfigDB.Users
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class GeneralSchema(SQLAlchemyAutoSchema):
proper_searcher_interval = EnumField(CheckPropersInterval)
nzb_method = EnumField(NzbMethod)
series_provider_default = EnumField(SeriesProviderID, by_value=True)
process_method = EnumField(ProcessMethod)
file_timestamp_timezone = EnumField(FileTimestampTimezone)
cpu_preset = EnumField(CpuPreset)
naming_multi_ep = EnumField(MultiEpNaming)
naming_anime_multi_ep = EnumField(MultiEpNaming)
default_page = EnumField(DefaultHomePage)
status_default = EnumField(EpisodeStatus)
status_default_after = EnumField(EpisodeStatus)
ep_default_deleted_status = EnumField(EpisodeStatus)
torrent_method = EnumField(TorrentMethod)
quality_default = EnumField(Qualities)
search_format_default = EnumField(SearchFormat)
class Meta:
model = ConfigDB.General
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class GUISchema(SQLAlchemyAutoSchema):
poster_sort_dir = EnumField(PosterSortDirection)
home_layout = EnumField(HomeLayout)
coming_eps_layout = EnumField(ComingEpsLayout)
coming_eps_sort = EnumField(ComingEpsSortBy)
poster_sort_by = EnumField(PosterSortBy)
history_layout = EnumField(HistoryLayout)
timezone_display = EnumField(TimezoneDisplay)
theme_name = EnumField(UITheme)
class Meta:
model = ConfigDB.GUI
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class BlackholeSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Blackhole
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class SABnzbdSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.SABnzbd
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class NZBgetSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.NZBget
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class SynologySchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Synology
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class TorrentSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Torrent
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class KodiSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Kodi
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class PlexSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Plex
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class EmbySchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Emby
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class GrowlSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Growl
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class FreeMobileSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.FreeMobile
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class TelegramSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Telegram
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class JoinSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Join
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class ProwlSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Prowl
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class TwitterSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Twitter
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class TwilioSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Twilio
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class Boxcar2Schema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Boxcar2
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class PushoverSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Pushover
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class LibnotifySchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Libnotify
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class NMJSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.NMJ
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class NMJv2Schema(SQLAlchemyAutoSchema):
db_loc = EnumField(NMJv2Location)
class Meta:
model = ConfigDB.NMJv2
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class SlackSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Slack
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class DiscordSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Discord
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class TraktSchema(SQLAlchemyAutoSchema):
method_add = EnumField(TraktAddMethod)
series_provider_default = EnumField(SeriesProviderID)
class Meta:
model = ConfigDB.Trakt
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class PyTivoSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.PyTivo
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class NMASchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.NMA
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class PushalotSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Pushalot
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class PushbulletSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Pushbullet
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class EmailSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Email
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class AlexaSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Alexa
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class SubtitlesSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.Subtitles
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class FailedDownloadsSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.FailedDownloads
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class FailedSnatchesSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.FailedSnatches
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class AniDBSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.AniDB
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class QualitySizesSchema(SQLAlchemyAutoSchema):
quality = EnumField(Qualities)
class Meta:
model = ConfigDB.QualitySizes
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class SearchProvidersTorrentSchema(SQLAlchemyAutoSchema):
provider_type = EnumField(SearchProviderType)
class Meta:
model = ConfigDB.SearchProvidersTorrent
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class SearchProvidersNzbSchema(SQLAlchemyAutoSchema):
provider_type = EnumField(SearchProviderType)
class Meta:
model = ConfigDB.SearchProvidersNzb
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class SearchProvidersTorrentRssSchema(SQLAlchemyAutoSchema):
provider_type = EnumField(SearchProviderType)
class Meta:
model = ConfigDB.SearchProvidersTorrentRss
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class SearchProvidersNewznabSchema(SQLAlchemyAutoSchema):
provider_type = EnumField(SearchProviderType)
class Meta:
model = ConfigDB.SearchProvidersNewznab
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class MetadataProvidersSchema(SQLAlchemyAutoSchema):
class Meta:
model = ConfigDB.MetadataProviders
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
================================================
FILE: sickrage/core/databases/main/__init__.py
================================================
# Author: echel0n
# URL: https://sickrage.ca
#
# This file is part of SiCKRAGE.
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
import datetime
from sqlalchemy import Column, Integer, Text, ForeignKeyConstraint, String, DateTime, Boolean, Index, Date, BigInteger, func, literal_column, Enum, exists
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
import sickrage
from sickrage.core.common import Qualities, EpisodeStatus
from sickrage.core.databases import SRDatabase, SRDatabaseBase, IntFlag
from sickrage.core.enums import SearchFormat, SeriesProviderID
class MainDB(SRDatabase):
base = declarative_base(cls=SRDatabaseBase)
def __init__(self, db_type, db_prefix, db_host, db_port, db_username, db_password):
super(MainDB, self).__init__('main', db_type, db_prefix, db_host, db_port, db_username, db_password)
def initialize(self):
self.base.metadata.create_all(self.engine)
def cleanup(self):
def remove_orphaned():
session = self.session()
# orphaned episode entries
for orphaned_result in session.query(self.TVEpisode).filter(~exists().where(self.TVEpisode.series_id == self.TVShow.series_id)):
sickrage.app.log.debug(f"Orphaned episode detected! episode_id: {orphaned_result.episode_id}")
sickrage.app.log.info(f"Deleting orphaned episode with episode_id: {orphaned_result.episode_id}")
session.delete(orphaned_result)
session.commit()
# orphaned imdb info entries
for orphaned_result in session.query(self.IMDbInfo).filter(~exists().where(self.IMDbInfo.series_id == self.TVShow.series_id)):
sickrage.app.log.debug(f"Orphaned imdb info detected! series_id: {orphaned_result.series_id}")
sickrage.app.log.info(f"Deleting orphaned imdb info with series_id: {orphaned_result.series_id}")
session.delete(orphaned_result)
session.commit()
# orphaned series provider mapping entries
for orphaned_result in session.query(self.SeriesProviderMapping).filter(~exists().where(self.SeriesProviderMapping.series_id == self.TVShow.series_id)):
sickrage.app.log.debug(f"Orphaned series provider mapper detected! series_id: {orphaned_result.series_id}")
sickrage.app.log.info(f"Deleting orphaned series provider mapper with series_id: {orphaned_result.series_id}")
session.delete(orphaned_result)
session.commit()
# orphaned whitelist entries
for orphaned_result in session.query(self.Whitelist).filter(~exists().where(self.Whitelist.series_id == self.TVShow.series_id)):
sickrage.app.log.debug(f"Orphaned whitelist detected! series_id: {orphaned_result.series_id}")
sickrage.app.log.info(f"Deleting orphaned whitelist with series_id: {orphaned_result.series_id}")
session.delete(orphaned_result)
session.commit()
# orphaned blacklist entries
for orphaned_result in session.query(self.Blacklist).filter(~exists().where(self.Blacklist.series_id == self.TVShow.series_id)):
sickrage.app.log.debug(f"Orphaned blacklist detected! series_id: {orphaned_result.series_id}")
sickrage.app.log.info(f"Deleting orphaned blacklist with series_id: {orphaned_result.series_id}")
session.delete(orphaned_result)
session.commit()
# orphaned history entries
for orphaned_result in session.query(self.History).filter(~exists().where(self.History.series_id == self.TVShow.series_id)):
sickrage.app.log.debug(f"Orphaned history detected! series_id: {orphaned_result.series_id}")
sickrage.app.log.info(f"Deleting orphaned history with series_id: {orphaned_result.series_id}")
session.delete(orphaned_result)
session.commit()
# orphaned failed snatch history entries
for orphaned_result in session.query(self.FailedSnatchHistory).filter(~exists().where(self.FailedSnatchHistory.series_id == self.TVShow.series_id)):
sickrage.app.log.debug(f"Orphaned failed snatch history detected! series_id: {orphaned_result.series_id}")
sickrage.app.log.info(f"Deleting orphaned failed snatch history with series_id: {orphaned_result.series_id}")
session.delete(orphaned_result)
session.commit()
# orphaned failed snatch entries
for orphaned_result in session.query(self.FailedSnatch).filter(~exists().where(self.FailedSnatch.series_id == self.TVShow.series_id)):
sickrage.app.log.debug(f"Orphaned failed snatch detected! series_id: {orphaned_result.series_id}")
sickrage.app.log.info(f"Deleting orphaned failed snatch with series_id: {orphaned_result.series_id}")
session.delete(orphaned_result)
session.commit()
def remove_duplicate_shows():
session = self.session()
# count by series id
duplicates = session.query(
self.TVShow.series_id,
func.count(self.TVShow.series_id).label('count')
).group_by(
self.TVShow.series_id
).having(literal_column('count') > 1).all()
for cur_duplicate in duplicates:
sickrage.app.log.debug("Duplicate show detected! series_id: {dupe_id} count: {dupe_count}".format(dupe_id=cur_duplicate.series_id,
dupe_count=cur_duplicate.count))
for result in session.query(self.TVShow).filter_by(series_id=cur_duplicate.series_id).limit(cur_duplicate.count - 1):
session.query(self.TVShow).filter_by(series_id=result.series_id).delete()
session.commit()
def remove_duplicate_episodes():
session = self.session()
# count by season/episode
duplicates = session.query(
self.TVEpisode.series_id,
self.TVEpisode.season,
self.TVEpisode.episode,
func.count(self.TVEpisode.episode_id).label('count')
).group_by(
self.TVEpisode.series_id,
self.TVEpisode.season,
self.TVEpisode.episode,
).having(literal_column('count') > 1).all()
for cur_duplicate in duplicates:
sickrage.app.log.debug("Duplicate episode detected! "
"series_id: {dupe_id} "
"season: {dupe_season} "
"episode {dupe_episode} count: {dupe_count}".format(dupe_id=cur_duplicate.series_id,
dupe_season=cur_duplicate.season,
dupe_episode=cur_duplicate.episode,
dupe_count=cur_duplicate.count))
for result in session.query(self.TVEpisode).filter_by(series_id=cur_duplicate.series_id,
season=cur_duplicate.season,
episode=cur_duplicate.episode).limit(cur_duplicate.count - 1):
session.query(self.TVEpisode).filter_by(series_id=result.series_id, season=result.season, episode=result.episode).delete()
session.commit()
# count by series id
duplicates = session.query(
self.TVEpisode.series_id,
self.TVEpisode.episode_id,
self.TVEpisode.season,
self.TVEpisode.episode,
func.count(self.TVEpisode.episode_id).label('count')
).group_by(
self.TVEpisode.series_id,
self.TVEpisode.episode_id
).having(literal_column('count') > 1).all()
for cur_duplicate in duplicates:
sickrage.app.log.debug("Duplicate episode detected! "
"series_id: {dupe_id} "
"season: {dupe_season} "
"episode {dupe_episode} count: {dupe_count}".format(dupe_id=cur_duplicate.series_id,
dupe_season=cur_duplicate.season,
dupe_episode=cur_duplicate.episode,
dupe_count=cur_duplicate.count))
for result in session.query(self.TVEpisode).filter_by(series_id=cur_duplicate.series_id,
episode_id=cur_duplicate.episode_id).limit(cur_duplicate.count - 1):
session.query(self.TVEpisode).filter_by(series_id=result.series_id, episode_id=result.episode_id).delete()
session.commit()
def fix_duplicate_episode_scene_numbering():
session = self.session()
duplicates = session.query(
self.TVEpisode.series_id,
self.TVEpisode.scene_season,
self.TVEpisode.scene_episode,
func.count(self.TVEpisode.series_id).label('count')
).group_by(
self.TVEpisode.series_id,
self.TVEpisode.scene_season,
self.TVEpisode.scene_episode
).filter(
self.TVEpisode.scene_season != -1,
self.TVEpisode.scene_episode != -1
).having(literal_column('count') > 1)
for cur_duplicate in duplicates:
sickrage.app.log.debug("Duplicate episode scene numbering detected! "
"series_id: {dupe_id} "
"scene season: {dupe_scene_season} "
"scene episode {dupe_scene_episode} count: {dupe_count}".format(dupe_id=cur_duplicate.series_id,
dupe_scene_season=cur_duplicate.scene_season,
dupe_scene_episode=cur_duplicate.scene_episode,
dupe_count=cur_duplicate.count))
for result in session.query(self.TVEpisode).filter_by(series_id=cur_duplicate.series_id,
scene_season=cur_duplicate.scene_season,
scene_episode=cur_duplicate.scene_episode).limit(cur_duplicate.count - 1):
result.scene_season = -1
result.scene_episode = -1
session.commit()
def fix_duplicate_episode_scene_absolute_numbering():
session = self.session()
duplicates = session.query(
self.TVEpisode.series_id,
self.TVEpisode.scene_absolute_number,
func.count(self.TVEpisode.series_id).label('count')
).group_by(
self.TVEpisode.series_id,
self.TVEpisode.scene_absolute_number
).filter(
self.TVEpisode.scene_absolute_number != -1
).having(literal_column('count') > 1)
for cur_duplicate in duplicates:
sickrage.app.log.debug("Duplicate episode scene absolute numbering detected! "
"series_id: {dupe_id} "
"scene absolute number: {dupe_scene_absolute_number} "
"count: {dupe_count}".format(dupe_id=cur_duplicate.series_id,
dupe_scene_absolute_number=cur_duplicate.scene_absolute_number,
dupe_count=cur_duplicate.count))
for result in session.query(self.TVEpisode).filter_by(series_id=cur_duplicate.series_id,
scene_absolute_number=cur_duplicate.scene_absolute_number). \
limit(cur_duplicate.count - 1):
result.scene_absolute_number = -1
session.commit()
def remove_invalid_episodes():
session = self.session()
session.query(self.TVEpisode).filter_by(episode_id=0).delete()
session.commit()
def fix_invalid_scene_numbering():
session = self.session()
session.query(self.TVEpisode).filter_by(scene_season=0, scene_episode=0).update({
self.TVEpisode.scene_season: -1,
self.TVEpisode.scene_episode: -1
})
session.commit()
session.query(self.TVEpisode).filter_by(scene_absolute_number=0).update({
self.TVEpisode.scene_absolute_number: -1
})
session.commit()
session.query(self.TVEpisode).filter(self.TVEpisode.season == self.TVEpisode.scene_season,
self.TVEpisode.episode == self.TVEpisode.scene_episode).update({
self.TVEpisode.scene_season: -1,
self.TVEpisode.scene_episode: -1
})
session.commit()
session.query(self.TVEpisode).filter(self.TVEpisode.absolute_number == self.TVEpisode.scene_absolute_number).update({
self.TVEpisode.scene_absolute_number: -1
})
session.commit()
def fix_tvshow_table_columns():
session = self.session()
session.query(self.TVShow).filter_by(sub_use_sr_metadata=None).update({'sub_use_sr_metadata': False})
session.query(self.TVShow).filter_by(skip_downloaded=None).update({'skip_downloaded': False})
session.query(self.TVShow).filter_by(dvd_order=None).update({'dvd_order': False})
session.query(self.TVShow).filter_by(subtitles=None).update({'subtitles': False})
session.query(self.TVShow).filter_by(anime=None).update({'anime': False})
session.query(self.TVShow).filter_by(flatten_folders=None).update({'flatten_folders': False})
session.query(self.TVShow).filter_by(paused=None).update({'paused': False})
session.query(self.TVShow).filter_by(last_xem_refresh=None).update({'last_xem_refresh': datetime.datetime.now()})
session.commit()
remove_orphaned()
remove_duplicate_shows()
remove_duplicate_episodes()
remove_invalid_episodes()
fix_invalid_scene_numbering()
fix_duplicate_episode_scene_numbering()
fix_duplicate_episode_scene_absolute_numbering()
fix_tvshow_table_columns()
class TVShow(base):
__tablename__ = 'tv_shows'
series_id = Column(Integer, index=True, primary_key=True)
series_provider_id = Column(Enum(SeriesProviderID), index=True, primary_key=True)
name = Column(Text, default='')
location = Column(Text, default='')
network = Column(Text, default='')
genre = Column(Text, default='')
overview = Column(Text, default='')
classification = Column(Text, default='Scripted')
runtime = Column(Integer, default=0)
quality = Column(IntFlag(Qualities), default=Qualities.SD)
airs = Column(Text, default='')
status = Column(Text, default='')
flatten_folders = Column(Boolean, nullable=False, default=0)
paused = Column(Boolean, nullable=False, default=0)
search_format = Column(Enum(SearchFormat), default=SearchFormat.STANDARD)
scene = Column(Boolean, nullable=False, default=0)
anime = Column(Boolean, nullable=False, default=0)
subtitles = Column(Boolean, nullable=False, default=0)
dvd_order = Column(Boolean, nullable=False, default=0)
skip_downloaded = Column(Boolean, nullable=False, default=0)
startyear = Column(Integer, default=0)
lang = Column(Text, default='')
imdb_id = Column(Text, default='')
rls_ignore_words = Column(Text, default='')
rls_require_words = Column(Text, default='')
default_ep_status = Column(Enum(EpisodeStatus), default=EpisodeStatus.SKIPPED)
sub_use_sr_metadata = Column(Boolean, nullable=False, default=0)
notify_list = Column(Text, default='')
search_delay = Column(Integer, default=0)
scene_exceptions = Column(Text, default='')
last_refresh = Column(DateTime(timezone=True), default=datetime.datetime.now())
last_xem_refresh = Column(DateTime(timezone=True), default=datetime.datetime.now())
last_scene_exceptions_refresh = Column(DateTime(timezone=True), default=datetime.datetime.now())
last_update = Column(DateTime(timezone=True), default=datetime.datetime.now())
last_backlog_search = Column(DateTime(timezone=True), default=datetime.datetime.now())
last_proper_search = Column(DateTime(timezone=True), default=datetime.datetime.now())
episodes = relationship('TVEpisode', uselist=True, back_populates='show', cascade="all, delete-orphan", lazy='dynamic')
imdb_info = relationship('IMDbInfo', uselist=False, backref='tv_shows', cascade="all, delete-orphan")
series_provider_mapping = relationship('SeriesProviderMapping', uselist=False, backref='tv_shows', cascade="all, delete-orphan")
blacklist = relationship('Blacklist', uselist=False, backref='tv_shows', cascade="all, delete-orphan")
whitelist = relationship('Whitelist', uselist=False, backref='tv_shows', cascade="all, delete-orphan")
history = relationship('History', uselist=False, backref='tv_shows', cascade="all, delete-orphan")
failed_snatch_history = relationship('FailedSnatchHistory', uselist=False, backref='tv_shows', cascade="all, delete-orphan")
failed_snatches = relationship('FailedSnatch', uselist=False, backref='tv_shows', cascade="all, delete-orphan")
class TVEpisode(base):
__tablename__ = 'tv_episodes'
__table_args__ = (
ForeignKeyConstraint(['series_id', 'series_provider_id'], ['tv_shows.series_id', 'tv_shows.series_provider_id'], ondelete='CASCADE',
name=f'fk_{__tablename__}_series_id_series_provider_id'),
Index('idx_series_id_series_provider_id', 'series_id', 'series_provider_id'),
Index('idx_series_id_episode_id', 'series_id', 'episode_id'),
Index('idx_status_episode_airdate', 'status', 'episode', 'airdate'),
Index('idx_season_episode_status_airdate', 'season', 'episode', 'status', 'airdate'),
Index('idx_episode_id_airdate', 'episode_id', 'airdate'),
)
series_id = Column(Integer, index=True, primary_key=True)
series_provider_id = Column(Enum(SeriesProviderID), index=True, primary_key=True)
episode_id = Column(Integer, default=0)
season = Column(Integer, index=True, primary_key=True)
episode = Column(Integer, index=True, primary_key=True)
absolute_number = Column(Integer, default=-1)
scene_season = Column(Integer, default=-1)
scene_episode = Column(Integer, default=-1)
scene_absolute_number = Column(Integer, default=-1)
xem_season = Column(Integer, default=-1)
xem_episode = Column(Integer, default=-1)
xem_absolute_number = Column(Integer, default=-1)
name = Column(Text, default='')
description = Column(Text, default='')
subtitles = Column(Text, default='')
subtitles_searchcount = Column(Integer, default=0)
subtitles_lastsearch = Column(DateTime(timezone=True), default=func.current_timestamp())
airdate = Column(Date, default=datetime.datetime.min)
hasnfo = Column(Boolean, nullable=False, default=False)
hastbn = Column(Boolean, nullable=False, default=False)
status = Column(Enum(EpisodeStatus), default=EpisodeStatus.UNKNOWN)
location = Column(Text, default='')
file_size = Column(BigInteger, default=0)
release_name = Column(Text, default='')
is_proper = Column(Boolean, nullable=False, default=False)
version = Column(Integer, default=-1)
release_group = Column(Text, default='')
show = relationship('TVShow', uselist=False, back_populates='episodes')
class IMDbInfo(base):
__tablename__ = 'imdb_info'
__table_args__ = (
ForeignKeyConstraint(['series_id', 'imdb_id'], ['tv_shows.series_id', 'tv_shows.imdb_id'], ondelete='CASCADE',
name=f'fk_{__tablename__}_series_id_imdb_id'),
)
series_id = Column(Integer, primary_key=True)
imdb_id = Column(String(10), index=True, unique=True)
rated = Column(Text)
title = Column(Text)
production = Column(Text)
website = Column(Text)
writer = Column(Text)
actors = Column(Text)
type = Column(Text)
votes = Column(Text, nullable=False)
seasons = Column(Text)
poster = Column(Text)
director = Column(Text)
released = Column(Text)
awards = Column(Text)
genre = Column(Text, nullable=False)
rating = Column(Text, nullable=False)
language = Column(Text)
country = Column(Text)
runtime = Column(Text)
metascore = Column(Text)
year = Column(Text)
plot = Column(Text)
last_update = Column(DateTime(timezone=True), default=datetime.datetime.now())
class SeriesProviderMapping(base):
__tablename__ = 'series_provider_mapping'
__table_args__ = (
ForeignKeyConstraint(['series_id', 'series_provider_id'], ['tv_shows.series_id', 'tv_shows.series_provider_id'], ondelete='CASCADE',
name=f'fk_{__tablename__}_series_id_series_provider_id'),
)
series_id = Column(Integer, primary_key=True)
series_provider_id = Column(Enum(SeriesProviderID), primary_key=True)
mapped_series_id = Column(Integer, nullable=False)
mapped_series_provider_id = Column(Enum(SeriesProviderID), primary_key=True)
class Blacklist(base):
__tablename__ = 'blacklist'
__table_args__ = (
ForeignKeyConstraint(['series_id', 'series_provider_id'], ['tv_shows.series_id', 'tv_shows.series_provider_id'], ondelete='CASCADE',
name=f'fk_{__tablename__}_series_id_series_provider_id'),
)
id = Column(Integer, autoincrement=True, primary_key=True)
series_id = Column(Integer, nullable=False)
series_provider_id = Column(Enum(SeriesProviderID), nullable=False)
keyword = Column(Text, nullable=False)
class Whitelist(base):
__tablename__ = 'whitelist'
__table_args__ = (
ForeignKeyConstraint(['series_id', 'series_provider_id'], ['tv_shows.series_id', 'tv_shows.series_provider_id'], ondelete='CASCADE',
name=f'fk_{__tablename__}_series_id_series_provider_id'),
)
id = Column(Integer, autoincrement=True, primary_key=True)
series_id = Column(Integer, nullable=False)
series_provider_id = Column(Enum(SeriesProviderID), nullable=False)
keyword = Column(Text, nullable=False)
class History(base):
__tablename__ = 'history'
__table_args__ = (
ForeignKeyConstraint(['series_id', 'series_provider_id'], ['tv_shows.series_id', 'tv_shows.series_provider_id'], ondelete='CASCADE',
name=f'fk_{__tablename__}_series_id_series_provider_id'),
)
id = Column(Integer, autoincrement=True, primary_key=True)
series_id = Column(Integer, nullable=False)
series_provider_id = Column(Enum(SeriesProviderID), nullable=False)
season = Column(Integer, nullable=False)
episode = Column(Integer, nullable=False)
resource = Column(Text, nullable=False, index=True)
action = Column(Integer, nullable=False)
version = Column(Integer, default=-1)
provider = Column(Text, nullable=False)
date = Column(DateTime, nullable=False)
quality = Column(IntFlag(Qualities), nullable=False)
release_group = Column(Text, nullable=False)
class FailedSnatchHistory(base):
__tablename__ = 'failed_snatch_history'
__table_args__ = (
ForeignKeyConstraint(['series_id', 'series_provider_id'], ['tv_shows.series_id', 'tv_shows.series_provider_id'], ondelete='CASCADE',
name=f'fk_{__tablename__}_series_id_series_provider_id'),
)
id = Column(Integer, autoincrement=True, primary_key=True)
series_id = Column(Integer, nullable=False)
series_provider_id = Column(Enum(SeriesProviderID), nullable=False)
date = Column(DateTime, nullable=False)
size = Column(Integer, nullable=False)
release = Column(Text, nullable=False, index=True)
provider = Column(Text, nullable=False)
season = Column(Integer, nullable=False)
episode = Column(Integer, nullable=False)
old_status = Column(Enum(EpisodeStatus), nullable=False)
class FailedSnatch(base):
__tablename__ = 'failed_snatches'
__table_args__ = (
ForeignKeyConstraint(['series_id', 'series_provider_id'], ['tv_shows.series_id', 'tv_shows.series_provider_id'], ondelete='CASCADE',
name=f'fk_{__tablename__}_series_id_series_provider_id'),
)
id = Column(Integer, autoincrement=True, primary_key=True)
series_id = Column(Integer, nullable=False)
series_provider_id = Column(Enum(SeriesProviderID), nullable=False)
release = Column(Text, nullable=False, index=True)
size = Column(Integer, nullable=False)
provider = Column(Text, nullable=False)
================================================
FILE: sickrage/core/databases/main/migrations/env.py
================================================
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
# fileConfig(config.config_file_name)
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = None
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection, target_metadata=target_metadata
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
================================================
FILE: sickrage/core/databases/main/migrations/script.py.mako
================================================
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
def upgrade():
${upgrades if upgrades else "pass"}
def downgrade():
${downgrades if downgrades else "pass"}
================================================
FILE: sickrage/core/databases/main/migrations/versions/001_Add_Initial_Tables.py
================================================
"""Initial migration
Revision ID: 1
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '1'
down_revision = None
def upgrade():
pass
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/002_Add_Last_Backlog_Search_Column_To_TVShow_Table.py
================================================
"""Initial migration
Revision ID: 2
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '2'
down_revision = '1'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
tv_shows = sa.Table('tv_shows', meta, autoload=True)
if not hasattr(tv_shows.c, 'last_backlog_search'):
op.add_column('tv_shows', sa.Column('last_backlog_search', sa.Integer, default=0))
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/003_Add_Last_Proper_Search_Column_To_TVShow_Table.py
================================================
"""Initial migration
Revision ID: 3
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '3'
down_revision = '2'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
tv_shows = sa.Table('tv_shows', meta, autoload=True)
if not hasattr(tv_shows.c, 'last_proper_search'):
op.add_column('tv_shows', sa.Column('last_proper_search', sa.Integer, default=0))
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/004_Rename_Columns_On_TVShow_Table.py
================================================
"""Initial migration
Revision ID: 4
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '4'
down_revision = '3'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
tv_shows = sa.Table('tv_shows', meta, autoload=True)
if hasattr(tv_shows.c, 'show_name'):
op.alter_column('tv_shows', 'show_name', new_column_name='name')
def downgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
tv_shows = sa.Table('tv_shows', meta, autoload=True)
if hasattr(tv_shows.c, 'name'):
op.alter_column('tv_shows', 'name', new_column_name='show_name')
================================================
FILE: sickrage/core/databases/main/migrations/versions/005_Rename_Columns_On_IMDbInfo_Table.py
================================================
"""Initial migration
Revision ID: 5
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '5'
down_revision = '4'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
imdb_info = sa.Table('imdb_info', meta, autoload=True)
with op.batch_alter_table("imdb_info") as batch_op:
if hasattr(imdb_info.c, 'imdbVotes'):
batch_op.alter_column('imdbVotes', new_column_name='votes')
if hasattr(imdb_info.c, 'imdbRating'):
batch_op.alter_column('imdbRating', new_column_name='rating')
if hasattr(imdb_info.c, 'Rated'):
batch_op.alter_column('Rated', new_column_name='rated')
if hasattr(imdb_info.c, 'Title'):
batch_op.alter_column('Title', new_column_name='title')
if hasattr(imdb_info.c, 'DVD'):
batch_op.alter_column('DVD', new_column_name='dvd')
if hasattr(imdb_info.c, 'Production'):
batch_op.alter_column('Production', new_column_name='production')
if hasattr(imdb_info.c, 'Website'):
batch_op.alter_column('Website', new_column_name='website')
if hasattr(imdb_info.c, 'Writer'):
batch_op.alter_column('Writer', new_column_name='writer')
if hasattr(imdb_info.c, 'Actors'):
batch_op.alter_column('Actors', new_column_name='actors')
if hasattr(imdb_info.c, 'Type'):
batch_op.alter_column('Type', new_column_name='type')
if hasattr(imdb_info.c, 'totalSeasons'):
batch_op.alter_column('totalSeasons', new_column_name='seasons')
if hasattr(imdb_info.c, 'Poster'):
batch_op.alter_column('Poster', new_column_name='poster')
if hasattr(imdb_info.c, 'Director'):
batch_op.alter_column('Director', new_column_name='director')
if hasattr(imdb_info.c, 'Released'):
batch_op.alter_column('Released', new_column_name='released')
if hasattr(imdb_info.c, 'Awards'):
batch_op.alter_column('Awards', new_column_name='awards')
if hasattr(imdb_info.c, 'Genre'):
batch_op.alter_column('Genre', new_column_name='genre')
if hasattr(imdb_info.c, 'Language'):
batch_op.alter_column('Language', new_column_name='language')
if hasattr(imdb_info.c, 'Country'):
batch_op.alter_column('Country', new_column_name='country')
if hasattr(imdb_info.c, 'Runtime'):
batch_op.alter_column('Runtime', new_column_name='runtime')
if hasattr(imdb_info.c, 'imdbID'):
batch_op.alter_column('imdbID', new_column_name='imdb_id')
if hasattr(imdb_info.c, 'Metascore'):
batch_op.alter_column('Metascore', new_column_name='metascore')
if hasattr(imdb_info.c, 'Year'):
batch_op.alter_column('Year', new_column_name='year')
if hasattr(imdb_info.c, 'Plot'):
batch_op.alter_column('Plot', new_column_name='plot')
def downgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
imdb_info = sa.Table('imdb_info', meta, autoload=True)
with op.batch_alter_table("imdb_info") as batch_op:
if hasattr(imdb_info.c, 'votes'):
batch_op.alter_column('votes', new_column_name='imdbVotes')
if hasattr(imdb_info.c, 'rating'):
batch_op.alter_column('rating', new_column_name='imdbRating')
if hasattr(imdb_info.c, 'rated'):
batch_op.alter_column('rated', new_column_name='Rated')
if hasattr(imdb_info.c, 'title'):
batch_op.alter_column('title', new_column_name='Title')
if hasattr(imdb_info.c, 'dvd'):
batch_op.alter_column('dvd', new_column_name='DVD')
if hasattr(imdb_info.c, 'production'):
batch_op.alter_column('production', new_column_name='Production')
if hasattr(imdb_info.c, 'website'):
batch_op.alter_column('website', new_column_name='Website')
if hasattr(imdb_info.c, 'writer'):
batch_op.alter_column('writer', new_column_name='Writer')
if hasattr(imdb_info.c, 'actors'):
batch_op.alter_column('actors', new_column_name='Actors')
if hasattr(imdb_info.c, 'typr'):
batch_op.alter_column('type', new_column_name='Type')
if hasattr(imdb_info.c, 'seasons'):
batch_op.alter_column('season', new_column_name='totalSeasons')
if hasattr(imdb_info.c, 'poster'):
batch_op.alter_column('poster', new_column_name='Poster')
if hasattr(imdb_info.c, 'director'):
batch_op.alter_column('director', new_column_name='Director')
if hasattr(imdb_info.c, 'released'):
batch_op.alter_column('released', new_column_name='Released')
if hasattr(imdb_info.c, 'awards'):
batch_op.alter_column('awards', new_column_name='Awards')
if hasattr(imdb_info.c, 'genre'):
batch_op.alter_column('genre', new_column_name='Genre')
if hasattr(imdb_info.c, 'language'):
batch_op.alter_column('language', new_column_name='Language')
if hasattr(imdb_info.c, 'country'):
batch_op.alter_column('country', new_column_name='Country')
if hasattr(imdb_info.c, 'runtime'):
batch_op.alter_column('runtime', new_column_name='Runtime')
if hasattr(imdb_info.c, 'imdb_id'):
batch_op.alter_column('imdb_id', new_column_name='imdbID')
if hasattr(imdb_info.c, 'metascore'):
batch_op.alter_column('metascore', new_column_name='Metascore')
if hasattr(imdb_info.c, 'year'):
batch_op.alter_column('year', new_column_name='Year')
if hasattr(imdb_info.c, 'plot'):
batch_op.alter_column('plot', new_column_name='Plot')
================================================
FILE: sickrage/core/databases/main/migrations/versions/006_Rename_Columns_On_TVEpisode_Table.py
================================================
"""Rename Columns On TV Episodes Table
Revision ID: 6
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '6'
down_revision = '5'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
tv_episodes = sa.Table('tv_episodes', meta, autoload=True)
if hasattr(tv_episodes.c, 'indexerid'):
op.alter_column('tv_episodes', 'indexerid', new_column_name='indexer_id')
if 'idx_indexerid_airdate' in tv_episodes.indexes:
op.drop_index('idx_indexerid_airdate', 'tv_episodes')
op.create_index('idx_indexer_id_airdate', 'tv_episodes', ['indexer_id', 'airdate'])
def downgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
tv_episodes = sa.Table('tv_episodes', meta, autoload=True)
if hasattr(tv_episodes.c, 'indexer_id'):
op.alter_column('tv_episodes', 'indexer_id', new_column_name='indexerid')
if 'idx_indexer_id_airdate' in tv_episodes.indexes:
op.drop_index('idx_indexer_id_airdate', 'tv_episodes')
op.create_index('idx_indexerid_airdate', 'tv_episodes', ['indexerid', 'airdate'])
================================================
FILE: sickrage/core/databases/main/migrations/versions/007_Convert_Airdate_Column_To_Date_Type_On_TVEpisode_Table.py
================================================
"""Initial migration
Revision ID: 7
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import datetime
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '7'
down_revision = '6'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
tv_episodes = sa.Table('tv_episodes', meta, autoload=True)
with op.batch_alter_table("tv_episodes") as batch_op:
batch_op.alter_column('airdate', type_=sa.String(32))
with op.get_context().begin_transaction():
for row in conn.execute(tv_episodes.select()):
date = datetime.date.fromordinal(int(row.airdate))
conn.execute(f'UPDATE tv_episodes SET airdate = "{date}" WHERE tv_episodes.indexer_id = {row.indexer_id}')
with op.batch_alter_table("tv_episodes") as batch_op:
batch_op.alter_column('airdate', type_=sa.Date)
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/008_Convert_Date_Column_To_DateTime_Type_On_FailedSnatchHistory_Table.py
================================================
"""Initial migration
Revision ID: 8
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import datetime
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '8'
down_revision = '7'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
failed_snatch_history = sa.Table('failed_snatch_history', meta, autoload=True)
op.alter_column('failed_snatch_history', 'date', type_=sa.String(32))
date_format = '%Y%m%d%H%M%S'
with op.get_context().begin_transaction():
for row in conn.execute(failed_snatch_history.select()):
date = datetime.datetime.strptime(str(row.date), date_format)
conn.execute(f'UPDATE failed_snatch_history SET date = {date} WHERE failed_snatch_history.id = {row.id}')
op.alter_column('failed_snatch_history', 'date', type_=sa.DateTime)
def downgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
failed_snatch_history = sa.Table('failed_snatch_history', meta, autoload=True)
op.alter_column('failed_snatch_history', 'date', type_=sa.String(32))
with op.get_context().begin_transaction():
for row in conn.execute(failed_snatch_history.select()):
date = str(row.date.toordinal())
conn.execute(f'UPDATE failed_snatch_history SET date = {date} WHERE failed_snatch_history.id = {row.id}')
op.alter_column('failed_snatch_history', 'date', type_=sa.Integer)
================================================
FILE: sickrage/core/databases/main/migrations/versions/009_Convert_Date_Column_To_DateTime_Type_On_History_Table.py
================================================
"""Initial migration
Revision ID: 9
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import datetime
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '9'
down_revision = '8'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
history = sa.Table('history', meta, autoload=True)
op.alter_column('history', 'date', type_=sa.String(32))
date_format = '%Y%m%d%H%M%S'
with op.get_context().begin_transaction():
for row in conn.execute(history.select()):
date = datetime.datetime.strptime(str(row.date), date_format)
conn.execute(f'UPDATE history SET date = "{date}" WHERE history.id = {row.id}')
op.alter_column('history', 'date', type_=sa.DateTime)
def downgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
history = sa.Table('history', meta, autoload=True)
op.alter_column('history', 'date', type_=sa.String(32))
with op.get_context().begin_transaction():
for row in conn.execute(history.select()):
date = str(row.date.toordinal())
conn.execute(f'UPDATE history SET date = {date} WHERE history.id = {row.id}')
op.alter_column('history', 'date', type_=sa.Integer)
================================================
FILE: sickrage/core/databases/main/migrations/versions/010_Add_Release_Group_Column_To_History_Table.py
================================================
"""Initial migration
Revision ID: 10
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '10'
down_revision = '9'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
history = sa.Table('history', meta, autoload=True)
if not hasattr(history.c, 'release_group'):
op.add_column('history', sa.Column('release_group', sa.Text, default=''))
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/011_Add_Scene_Exceptions_Column_To_TVShow_Table.py
================================================
"""Initial migration
Revision ID: 11
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '11'
down_revision = '10'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
tv_shows = sa.Table('tv_shows', meta, autoload=True)
if not hasattr(tv_shows.c, 'scene_exceptions'):
op.add_column('tv_shows', sa.Column('scene_exceptions', sa.Text, default=''))
if not hasattr(tv_shows.c, 'last_scene_exceptions_refresh'):
op.add_column('tv_shows', sa.Column('last_scene_exceptions_refresh', sa.Integer, default=0))
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/012_Add_Search_Format_Column_To_TVShow_Table.py
================================================
"""Initial migration
Revision ID: 12
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '12'
down_revision = '11'
class SearchFormats(object):
STANDARD = 1
AIR_BY_DATE = 2
ANIME = 3
SPORTS = 4
COLLECTION = 6
search_format_strings = {
STANDARD: 'Standard (Show.S01E01)',
AIR_BY_DATE: 'Air By Date (Show.2010.03.02)',
ANIME: 'Anime (Show.265)',
SPORTS: 'Sports (Show.2010.03.02)',
COLLECTION: 'Collection (Show.Series.1.1of10) or (Show.Series.1.Part.1)'
}
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
tv_shows = sa.Table('tv_shows', meta, autoload=True)
if not hasattr(tv_shows.c, 'search_format'):
op.add_column('tv_shows', sa.Column('search_format', sa.Integer, default=0))
with op.get_context().begin_transaction():
for row in conn.execute(tv_shows.select()):
if row.anime == 1 and not row.scene == 1:
value = SearchFormats.ANIME
elif row.anime == 1 and row.scene == 1:
value = 5
elif row.sports == 1:
value = SearchFormats.SPORTS
elif row.air_by_date == 1:
value = SearchFormats.AIR_BY_DATE
elif row.scene == 1:
value = 5
else:
value = SearchFormats.STANDARD
conn.execute(f'UPDATE tv_shows SET search_format = {value} WHERE tv_shows.indexer_id = {row.indexer_id}')
with op.batch_alter_table('tv_shows') as batch_op:
if hasattr(tv_shows.c, 'sports'):
batch_op.drop_column('sports')
if hasattr(tv_shows.c, 'air_by_date'):
batch_op.drop_column('air_by_date')
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/013_Add_Scene_Column_To_TVShow_Table.py
================================================
"""Initial migration
Revision ID: 13
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '13'
down_revision = '12'
class SearchFormats(object):
STANDARD = 1
AIR_BY_DATE = 2
ANIME = 3
SPORTS = 4
COLLECTION = 6
search_format_strings = {
STANDARD: 'Standard (Show.S01E01)',
AIR_BY_DATE: 'Air By Date (Show.2010.03.02)',
ANIME: 'Anime (Show.265)',
SPORTS: 'Sports (Show.2010.03.02)',
COLLECTION: 'Collection (Show.Series.1.1of10) or (Show.Series.1.Part.1)'
}
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
tv_shows = sa.Table('tv_shows', meta, autoload=True)
if not hasattr(tv_shows.c, 'scene'):
op.add_column('tv_shows', sa.Column('scene', sa.Boolean))
with op.get_context().begin_transaction():
for row in conn.execute(tv_shows.select()):
if row.search_format == 5:
conn.execute(f'UPDATE tv_shows SET scene = 1 WHERE tv_shows.indexer_id = {row.indexer_id}')
conn.execute(f'UPDATE tv_shows SET search_format = {SearchFormats.STANDARD} WHERE tv_shows.indexer_id = {row.indexer_id}')
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/014_Add_Last_XEM_Refresh_Column_To_TVShows_Table.py
================================================
"""Initial migration
Revision ID: 14
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import datetime
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '14'
down_revision = '13'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
tv_shows = sa.Table('tv_shows', meta, autoload=True)
xem_refresh = sa.Table('xem_refresh', meta, autoload=True)
if not hasattr(tv_shows.c, 'last_xem_refresh'):
op.add_column('tv_shows', sa.Column('last_xem_refresh', sa.Integer, default=datetime.datetime.now().toordinal()))
with op.get_context().begin_transaction():
for row in conn.execute(xem_refresh.select()):
last_xem_refresh = row.last_refreshed or datetime.datetime.now().toordinal()
conn.execute(f'UPDATE tv_shows SET last_xem_refresh = {last_xem_refresh} WHERE tv_shows.indexer_id = {row.indexer_id}')
op.drop_table('xem_refresh')
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/015_Add_XEM_Numbering_To_TVEpisodes_Table.py
================================================
"""Initial migration
Revision ID: 15
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '15'
down_revision = '14'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
tv_episodes = sa.Table('tv_episodes', meta, autoload=True)
with op.batch_alter_table("tv_episodes") as batch_op:
if not hasattr(tv_episodes.c, 'xem_season'):
batch_op.add_column(sa.Column('xem_season', sa.Integer, default=-1))
if not hasattr(tv_episodes.c, 'xem_episode'):
batch_op.add_column(sa.Column('xem_episode', sa.Integer, default=-1))
if not hasattr(tv_episodes.c, 'xem_absolute_number'):
batch_op.add_column(sa.Column('xem_absolute_number', sa.Integer, default=-1))
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/016_Merge_Scene_Numbering_Table_With_TVEpisodes_Table.py
================================================
"""Initial migration
Revision ID: 16
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
from sqlalchemy import inspect
revision = '16'
down_revision = '15'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
if inspect(conn).has_table('scene_numbering'):
scene_numbering = sa.Table('scene_numbering', meta, autoload=True)
with op.get_context().begin_transaction():
for row in conn.execute(scene_numbering.select()):
conn.execute(
f'UPDATE tv_episodes SET scene_season = {row.scene_season} WHERE tv_episodes.showid = {row.indexer_id} and tv_episodes.season = {row.season} and tv_episodes.episode = {row.episode}')
conn.execute(
f'UPDATE tv_episodes SET scene_episode = {row.scene_episode} WHERE tv_episodes.showid = {row.indexer_id} and tv_episodes.season = {row.season} and tv_episodes.episode = {row.episode}')
op.drop_table('scene_numbering')
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/017_Convert_SearchFormat_Column_To_Enum_Type_On_TVShow_Table.py
================================================
"""Initial migration
Revision ID: 17
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import enum
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '17'
down_revision = '16'
class SearchFormat(enum.Enum):
STANDARD = 1
AIR_BY_DATE = 2
ANIME = 3
SPORTS = 4
COLLECTION = 6
def upgrade():
conn = op.get_bind()
for item in SearchFormat:
conn.execute(f'UPDATE tv_shows SET search_format = "{item.name}" WHERE search_format = {item.value}')
with op.batch_alter_table('tv_shows') as batch_op:
batch_op.alter_column('search_format', type_=sa.Enum(SearchFormat), default=SearchFormat.STANDARD)
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/018_Convert_Timestamp_Integer_Columns_To_DateTime_Type_On_TVEpisode_Table.py
================================================
"""Initial migration
Revision ID: 7
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import datetime
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '18'
down_revision = '17'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
tv_episodes = sa.Table('tv_episodes', meta, autoload=True)
with op.get_context().begin_transaction():
for row in conn.execute(tv_episodes.select()):
conn.execute(f'UPDATE tv_episodes SET subtitles_lastsearch = "" WHERE tv_episodes.indexer_id = {row.indexer_id}')
with op.batch_alter_table("tv_episodes") as batch_op:
batch_op.alter_column('subtitles_lastsearch', type_=sa.DateTime(timezone=True))
with op.get_context().begin_transaction():
for row in conn.execute(tv_episodes.select()):
conn.execute(f'UPDATE tv_episodes SET subtitles_lastsearch = {sa.func.current_timestamp()} WHERE tv_episodes.indexer_id = {row.indexer_id}')
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/019_Convert_Timestamp_Integer_Columns_To_DateTime_Type_On_TVShow_Table.py
================================================
"""Initial migration
Revision ID: 7
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import datetime
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '19'
down_revision = '18'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
tv_shows = sa.Table('tv_shows', meta, autoload=True)
with op.get_context().begin_transaction():
for row in conn.execute(tv_shows.select()):
conn.execute(f'UPDATE tv_shows SET last_refresh = "" WHERE tv_shows.indexer_id = {row.indexer_id}')
conn.execute(f'UPDATE tv_shows SET last_xem_refresh = "" WHERE tv_shows.indexer_id = {row.indexer_id}')
conn.execute(f'UPDATE tv_shows SET last_scene_exceptions_refresh = "" WHERE tv_shows.indexer_id = {row.indexer_id}')
conn.execute(f'UPDATE tv_shows SET last_update = "" WHERE tv_shows.indexer_id = {row.indexer_id}')
conn.execute(f'UPDATE tv_shows SET last_backlog_search = "" WHERE tv_shows.indexer_id = {row.indexer_id}')
conn.execute(f'UPDATE tv_shows SET last_proper_search = "" WHERE tv_shows.indexer_id = {row.indexer_id}')
with op.batch_alter_table("tv_shows") as batch_op:
batch_op.alter_column('last_refresh', type_=sa.DateTime(timezone=True))
batch_op.alter_column('last_xem_refresh', type_=sa.DateTime(timezone=True))
batch_op.alter_column('last_scene_exceptions_refresh', type_=sa.DateTime(timezone=True))
batch_op.alter_column('last_update', type_=sa.DateTime(timezone=True))
batch_op.alter_column('last_backlog_search', type_=sa.DateTime(timezone=True))
batch_op.alter_column('last_proper_search', type_=sa.DateTime(timezone=True))
with op.get_context().begin_transaction():
for row in conn.execute(tv_shows.select()):
conn.execute(f'UPDATE tv_shows SET last_refresh = {sa.func.current_timestamp()} WHERE tv_shows.indexer_id = {row.indexer_id}')
conn.execute(f'UPDATE tv_shows SET last_xem_refresh = {sa.func.current_timestamp()} WHERE tv_shows.indexer_id = {row.indexer_id}')
conn.execute(f'UPDATE tv_shows SET last_scene_exceptions_refresh = {sa.func.current_timestamp()} WHERE tv_shows.indexer_id = {row.indexer_id}')
conn.execute(f'UPDATE tv_shows SET last_update = {sa.func.current_timestamp()} WHERE tv_shows.indexer_id = {row.indexer_id}')
conn.execute(f'UPDATE tv_shows SET last_backlog_search = {sa.func.current_timestamp()} WHERE tv_shows.indexer_id = {row.indexer_id}')
conn.execute(f'UPDATE tv_shows SET last_proper_search = {sa.func.current_timestamp()} WHERE tv_shows.indexer_id = {row.indexer_id}')
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/020_Convert_Timestamp_Integer_Columns_To_DateTime_Type_On_ImdbInfo_Table.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
"""Initial migration
Revision ID: 20
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import datetime
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '20'
down_revision = '19'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
imdb_info = sa.Table('imdb_info', meta, autoload=True)
with op.get_context().begin_transaction():
for row in conn.execute(imdb_info.select()):
conn.execute(f'UPDATE imdb_info SET last_update = "" WHERE imdb_info.indexer_id = {row.indexer_id}')
with op.batch_alter_table("imdb_info") as batch_op:
batch_op.alter_column('last_update', type_=sa.DateTime(timezone=True))
with op.get_context().begin_transaction():
for row in conn.execute(imdb_info.select()):
conn.execute(f'UPDATE imdb_info SET last_update = {sa.func.current_timestamp()} WHERE imdb_info.indexer_id = {row.indexer_id}')
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/021_Upgrade_To_SiCKRAGE_v10.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
"""Initial migration
Revision ID: 21
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import datetime
import enum
import sqlalchemy as sa
from alembic import op
from sickrage.core.common import Qualities, EpisodeStatus
from sickrage.core.databases import IntFlag
from sickrage.core.databases.main import MainDB
# revision identifiers, used by Alembic.
revision = '21'
down_revision = '20'
class SeriesProviderID(enum.Enum):
THETVDB = 1
def upgrade():
conn = op.get_bind()
maindb_meta = MainDB.base.metadata
maindb_meta.bind = conn
op.alter_column('tv_shows', 'indexer_id', new_column_name='series_id')
op.alter_column('tv_shows', 'indexer', new_column_name='series_provider_id')
op.alter_column('tv_shows', 'dvdorder', new_column_name='dvd_order')
op.alter_column('tv_episodes', 'showid', new_column_name='series_id')
op.alter_column('tv_episodes', 'indexer_id', new_column_name='episode_id')
op.alter_column('tv_episodes', 'indexer', new_column_name='series_provider_id')
op.alter_column('imdb_info', 'indexer_id', new_column_name='series_id')
for item in SeriesProviderID:
conn.execute(f'UPDATE tv_shows SET series_provider_id = "{item.name}" WHERE series_provider_id = {item.value}')
conn.execute(f'UPDATE tv_episodes SET series_provider_id = "{item.name}" WHERE series_provider_id = {item.value}')
for item in EpisodeStatus:
conn.execute(f'UPDATE tv_shows SET default_ep_status = "{item.name}" WHERE default_ep_status = {item.value}')
conn.execute(f'UPDATE tv_episodes SET status = "{item.name}" WHERE status = {item.value}')
with op.batch_alter_table('tv_shows') as batch_op:
batch_op.alter_column('series_provider_id', type_=sa.Enum(SeriesProviderID))
batch_op.alter_column('default_ep_status', type_=sa.Enum(EpisodeStatus))
batch_op.alter_column('quality', type_=IntFlag(Qualities))
with op.batch_alter_table('tv_episodes') as batch_op:
batch_op.alter_column('series_provider_id', type_=sa.Enum(SeriesProviderID))
batch_op.alter_column('status', type_=sa.Enum(EpisodeStatus))
tv_episodes_results = []
for x in conn.execute('SELECT * FROM tv_episodes'):
x = dict(x)
if 'airdate' in x:
try:
x['airdate'] = datetime.datetime.strptime(x['airdate'], '%Y-%m-%d')
except ValueError:
continue
if 'subtitles_lastsearch' in x:
try:
x['subtitles_lastsearch'] = datetime.datetime.now()
except ValueError:
continue
tv_episodes_results.append(x)
blacklist_results = []
for x in conn.execute('SELECT * FROM blacklist'):
x = dict(x)
x['series_provider_id'] = SeriesProviderID.THETVDB
blacklist_results.append(x)
whitelist_results = []
for x in conn.execute('SELECT * FROM whitelist'):
x = dict(x)
x['series_provider_id'] = SeriesProviderID.THETVDB
whitelist_results.append(x)
imdb_info_results = []
for x in conn.execute('SELECT * FROM imdb_info'):
x = dict(x)
x['last_update'] = datetime.datetime.now()
imdb_info_results.append(x)
op.drop_table('indexer_mapping')
op.drop_table('tv_episodes')
op.drop_table('imdb_info')
op.drop_table('blacklist')
op.drop_table('whitelist')
op.drop_table('history')
op.drop_table('failed_snatch_history')
op.drop_table('failed_snatches')
sa.Table('series_provider_mapping', maindb_meta, autoload=True).create()
sa.Table('tv_episodes', maindb_meta, autoload=True).create()
sa.Table('imdb_info', maindb_meta, autoload=True).create()
sa.Table('blacklist', maindb_meta, autoload=True).create()
sa.Table('whitelist', maindb_meta, autoload=True).create()
sa.Table('history', maindb_meta, autoload=True).create()
sa.Table('failed_snatch_history', maindb_meta, autoload=True).create()
sa.Table('failed_snatches', maindb_meta, autoload=True).create()
tv_episodes = sa.Table('tv_episodes', maindb_meta, autoload=True)
imdb_info = sa.Table('imdb_info', maindb_meta, autoload=True)
blacklist = sa.Table('blacklist', maindb_meta, autoload=True)
whitelist = sa.Table('whitelist', maindb_meta, autoload=True)
op.bulk_insert(tv_episodes, tv_episodes_results)
op.bulk_insert(imdb_info, imdb_info_results)
op.bulk_insert(blacklist, blacklist_results)
op.bulk_insert(whitelist, whitelist_results)
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/022_Convert_Language_Codes_To_ISO6393_On_TVShow_Table.py
================================================
"""Initial migration
Revision ID: 22
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import babelfish
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '22'
down_revision = '21'
def upgrade():
conn = op.get_bind()
meta = sa.MetaData(bind=conn)
tv_shows = sa.Table('tv_shows', meta, autoload=True)
with op.get_context().begin_transaction():
for row in conn.execute(tv_shows.select()):
if len(row.lang) == 2:
lang = babelfish.Language.fromalpha2(row.lang)
conn.execute(f'UPDATE tv_shows SET lang = "{lang.alpha3}" WHERE tv_shows.series_id = {row.series_id}')
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/migrations/versions/023_Bump_Version.py
================================================
"""Initial migration
Revision ID: 23
Revises:
Create Date: 2017-12-29 14:39:27.854291
"""
import babelfish
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '23'
down_revision = '22'
def upgrade():
pass
def downgrade():
pass
================================================
FILE: sickrage/core/databases/main/schemas.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
from marshmallow_enum import EnumField
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema
from sickrage.core.common import EpisodeStatus, Qualities
from sickrage.core.databases.main import MainDB
from sickrage.core.enums import SearchFormat, SeriesProviderID
from sickrage.core.helpers import camelcase
class TVShowSchema(SQLAlchemyAutoSchema):
search_format = EnumField(SearchFormat)
series_provider_id = EnumField(SeriesProviderID)
default_ep_status = EnumField(EpisodeStatus)
quality = EnumField(Qualities)
class Meta:
model = MainDB.TVShow
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class TVEpisodeSchema(SQLAlchemyAutoSchema):
series_provider_id = EnumField(SeriesProviderID)
status = EnumField(EpisodeStatus)
class Meta:
model = MainDB.TVEpisode
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class IMDbInfoSchema(SQLAlchemyAutoSchema):
class Meta:
model = MainDB.IMDbInfo
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class BlacklistSchema(SQLAlchemyAutoSchema):
series_provider_id = EnumField(SeriesProviderID)
class Meta:
model = MainDB.Blacklist
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class WhitelistSchema(SQLAlchemyAutoSchema):
series_provider_id = EnumField(SeriesProviderID)
class Meta:
model = MainDB.Whitelist
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class HistoryScheme(SQLAlchemyAutoSchema):
series_provider_id = EnumField(SeriesProviderID)
quality = EnumField(Qualities)
class Meta:
model = MainDB.History
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
class FailedSnatchHistoryScheme(SQLAlchemyAutoSchema):
series_provider_id = EnumField(SeriesProviderID)
old_status = EnumField(EpisodeStatus)
class Meta:
model = MainDB.FailedSnatchHistory
include_relationships = False
load_instance = True
def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
================================================
FILE: sickrage/core/enums.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import enum
class SeriesProviderID(enum.Enum):
THETVDB = 'thetvdb'
@property
def _strings(self):
return {
self.THETVDB.name: 'TheTVDB'
}
@property
def display_name(self):
return self._strings[self.name]
class DefaultHomePage(enum.Enum):
HOME = 'home'
SCHEDULE = 'schedule'
HISTORY = 'history'
@property
def _strings(self):
return {
self.HOME.name: 'Home',
self.SCHEDULE.name: 'Schedule',
self.HISTORY.name: 'History',
}
@property
def display_name(self):
return self._strings[self.name]
class MultiEpNaming(enum.Enum):
REPEAT = 1
EXTEND = 2
DUPLICATE = 4
LIMITED_EXTEND = 8
SEPARATED_REPEAT = 16
LIMITED_EXTEND_E_PREFIXED = 32
@property
def _strings(self):
return {
self.REPEAT.name: 'Repeat',
self.SEPARATED_REPEAT.name: 'Repeat (Separated)',
self.DUPLICATE.name: 'Duplicate',
self.EXTEND.name: 'Extend',
self.LIMITED_EXTEND.name: 'Extend (Limited)',
self.LIMITED_EXTEND_E_PREFIXED.name: 'Extend (Limited, E-prefixed)'
}
@property
def display_name(self):
return self._strings[self.name]
class CpuPreset(enum.Enum):
LOW = 0.01
NORMAL = 0.02
HIGH = 0.05
@property
def _strings(self):
return {
self.LOW.name: 'Low',
self.NORMAL.name: 'Normal',
self.HIGH.name: 'High',
}
@property
def display_name(self):
return self._strings[self.name]
class CheckPropersInterval(enum.Enum):
DAILY = 24 * 60
FOUR_HOURS = 4 * 60
NINETY_MINUTES = 90
FORTY_FIVE_MINUTES = 45
FIFTEEN_MINUTES = 15
@property
def _strings(self):
return {
self.DAILY.name: '24 hours',
self.FOUR_HOURS.name: '4 hours',
self.NINETY_MINUTES.name: '90 mins',
self.FORTY_FIVE_MINUTES.name: '45 mins',
self.FIFTEEN_MINUTES.name: '15 mins',
}
@property
def display_name(self):
return self._strings[self.name]
class FileTimestampTimezone(enum.Enum):
NETWORK = 0
LOCAL = 1
@property
def _strings(self):
return {
self.NETWORK.name: 'Network',
self.LOCAL.name: 'Local',
}
@property
def display_name(self):
return self._strings[self.name]
class ProcessMethod(enum.Enum):
COPY = 'copy'
MOVE = 'move'
HARDLINK = 'hardlink'
SYMLINK = 'symlink'
SYMLINK_REVERSED = 'symlink_reversed'
@property
def _strings(self):
return {
self.COPY.name: 'Copy',
self.MOVE.name: 'Move',
self.HARDLINK.name: 'Hard Link',
self.SYMLINK.name: 'Symbolic Link',
self.SYMLINK_REVERSED.name: 'Symbolic Link Reversed',
}
@property
def display_name(self):
return self._strings[self.name]
class NzbMethod(enum.Enum):
BLACKHOLE = 'blackhole'
SABNZBD = 'sabnzbd'
NZBGET = 'nzbget'
DOWNLOAD_STATION = 'download_station'
@property
def _strings(self):
return {
self.BLACKHOLE.name: 'Blackhole',
self.SABNZBD.name: 'SABnzbd',
self.NZBGET.name: 'NZBget',
self.DOWNLOAD_STATION.name: 'Synology DS',
}
@property
def display_name(self):
return self._strings[self.name]
class TorrentMethod(enum.Enum):
BLACKHOLE = 'blackhole'
UTORRENT = 'utorrent'
TRANSMISSION = 'transmission'
DELUGE = 'deluge'
DELUGED = 'deluged'
DOWNLOAD_STATION = 'download_station'
RTORRENT = 'rtorrent'
QBITTORRENT = 'qbittorrent'
MLNET = 'mlnet'
PUTIO = 'putio'
@property
def _strings(self):
return {
self.BLACKHOLE.name: 'Blackhole',
self.UTORRENT.name: 'uTorrent',
self.TRANSMISSION.name: 'Transmission',
self.DELUGE.name: 'Deluge (via WebUI)',
self.DELUGED.name: 'Deluge (via Daemon)',
self.DOWNLOAD_STATION.name: 'Synology DS',
self.RTORRENT.name: 'rTorrent',
self.QBITTORRENT.name: 'qBitTorrent',
self.MLNET.name: 'MLDonkey',
self.PUTIO.name: 'Putio',
}
@property
def display_name(self):
return self._strings[self.name]
class SearchFormat(enum.Enum):
STANDARD = 1
AIR_BY_DATE = 2
ANIME = 3
SPORTS = 4
COLLECTION = 6
@property
def _strings(self):
return {
self.STANDARD.name: 'Standard (Show.S01E01)',
self.AIR_BY_DATE.name: 'Air By Date (Show.2010.03.02)',
self.ANIME.name: 'Anime (Show.265)',
self.SPORTS.name: 'Sports (Show.2010.03.02)',
self.COLLECTION.name: 'Collection (Show.Series.1.1of10) or (Show.Series.1.Part.1)'
}
@property
def display_name(self):
return self._strings[self.name]
class UserPermission(enum.Enum):
SUPERUSER = 0
GUEST = 1
@property
def _strings(self):
return {
self.SUPERUSER.name: 'Superuser',
self.GUEST.name: 'Guest',
}
@property
def display_name(self):
return self._strings[self.name]
class PosterSortDirection(enum.Enum):
ASCENDING = 0
DESCENDING = 1
@property
def _strings(self):
return {
self.ASCENDING.name: 'Ascending',
self.DESCENDING.name: 'Descending',
}
@property
def display_name(self):
return self._strings[self.name]
class HomeLayout(enum.Enum):
POSTER = 'poster'
SMALL = 'small'
BANNER = 'banner'
DETAILED = 'detailed'
SIMPLE = 'simple'
@property
def _strings(self):
return {
self.POSTER.name: 'Poster',
self.SMALL.name: 'Small Poster',
self.BANNER.name: 'Banner',
self.DETAILED.name: 'Detailed',
self.SIMPLE.name: 'Simple',
}
@property
def display_name(self):
return self._strings[self.name]
class PosterSortBy(enum.Enum):
NAME = 0
DATE = 1
NETWORK = 2
PROGRESS = 3
@property
def _strings(self):
return {
self.NAME.name: 'Sort By Name',
self.DATE.name: 'Sort By Date',
self.NETWORK.name: 'Sort By Network',
self.PROGRESS.name: 'Sort By Progress',
}
@property
def display_name(self):
return self._strings[self.name]
class HistoryLayout(enum.Enum):
DETAILED = 'detailed'
COMPACT = 'compact'
@property
def _strings(self):
return {
self.DETAILED.name: 'Detailed',
self.COMPACT.name: 'Compact',
}
@property
def display_name(self):
return self._strings[self.name]
class TimezoneDisplay(enum.Enum):
LOCAL = 0
NETWORK = 1
@property
def _strings(self):
return {
self.LOCAL.name: 'Local',
self.NETWORK.name: 'Network',
}
@property
def display_name(self):
return self._strings[self.name]
class UITheme(enum.Enum):
DARK = 'dark'
LIGHT = 'light'
@property
def _strings(self):
return {
self.DARK.name: 'Dark',
self.LIGHT.name: 'Light',
}
@property
def display_name(self):
return self._strings[self.name]
class TraktAddMethod(enum.Enum):
SKIP_ALL = 0
DOWNLOAD_PILOT_ONLY = 1
WHOLE_SHOW = 2
@property
def _strings(self):
return {
self.SKIP_ALL.name: 'Skip All',
self.DOWNLOAD_PILOT_ONLY.name: 'Download Pilot Only',
self.WHOLE_SHOW.name: 'Get Whole Show',
}
@property
def display_name(self):
return self._strings[self.name]
================================================
FILE: sickrage/core/exceptions/__init__.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
class SiCKRAGEException(Exception):
"""
Generic SiCKRAGE Exception - should never be thrown, only sub-classed
"""
class SiCKRAGETVShowException(SiCKRAGEException):
"""
Generic SiCKRAGE TVShow Exception - should never be thrown, only sub-classed
"""
class SiCKRAGETVEpisodeException(SiCKRAGEException):
"""
Generic SiCKRAGE TVEpisode Exception - should never be thrown, only sub-classed
"""
class AuthException(SiCKRAGEException):
"""
Your authentication information are incorrect
"""
class CantRefreshShowException(SiCKRAGEException):
"""
The show can't be refreshed right now
"""
class CantRemoveShowException(SiCKRAGEException):
"""
The show can't removed right now
"""
class CantUpdateShowException(SiCKRAGEException):
"""
The show can't be updated right now
"""
class EpisodeDeletedException(SiCKRAGETVEpisodeException):
"""
This episode has been deleted
"""
class EpisodeNotFoundException(SiCKRAGETVEpisodeException):
"""
The episode wasn't found on the series provider
"""
class EpisodePostProcessingFailedException(SiCKRAGEException):
"""
The episode post-processing failed
"""
class EpisodeDirectoryNotFoundException(SiCKRAGETVEpisodeException):
"""
The episode directory was not found
"""
class FailedPostProcessingFailedException(SiCKRAGEException):
"""
The failed post-processing failed
"""
class MultipleEpisodesInDatabaseException(SiCKRAGETVEpisodeException):
"""
Multiple episodes were found in the database! The database must be fixed first
"""
class MultipleShowsInDatabaseException(SiCKRAGETVShowException):
"""
Multiple shows were found in the database! The database must be fixed first
"""
class MultipleShowObjectsException(SiCKRAGETVShowException):
"""
Multiple objects for the same show were found! Something is very wrong
"""
class NoNFOException(SiCKRAGEException):
"""
No NFO was found
"""
class ShowNotFoundException(SiCKRAGETVShowException):
"""
The show wasn't found
"""
class NoFreeSpaceException(SiCKRAGEException):
"""
No free space left
"""
class AnidbAdbaConnectionException(SiCKRAGEException):
"""
Connection exceptions raised while trying to communicate with the Anidb UDP api.
More info on the api: https://wiki.anidb.net/w/API.
"""
================================================
FILE: sickrage/core/google_drive.py
================================================
import os
from base64 import b64decode
from tornado.escape import json_encode
import sickrage
currentInfo = ''
percentDone = 0
class GoogleDrive(object):
def __init__(self):
self.reset_progress()
def reset_progress(self):
self.set_progress('Syncing', 0)
def set_progress(self, current_info, percent_done):
global currentInfo, percentDone
currentInfo = current_info
percentDone = percent_done
@staticmethod
def get_progress():
return json_encode({'percent_done': percentDone, 'current_info': currentInfo})
def walk_drive(self, folder_id):
dirs, nondirs = {}, {}
for item in sickrage.app.api.google.list_files(folder_id)['data']:
if item['type'] == "application/vnd.google-apps.folder":
dirs.update({str(item['id']): item['name']})
else:
nondirs.update({str(item['id']): item['name']})
yield folder_id, dirs, nondirs
for name in dirs.keys():
for x in self.walk_drive(name):
yield x
def sync_remote(self):
main_folder = 'appDataFolder'
folder_id = sickrage.app.api.google.search_files(main_folder, sickrage.app.config.user.sub_id)['data']
local_dirs = set()
local_files = set()
# sync local drive to google drive
for root, dirs, files in os.walk(sickrage.app.data_dir):
local_dirs.update(dirs)
local_files.update(files)
folder = root.replace(sickrage.app.data_dir, '{}/{}'.format(main_folder, sickrage.app.config.user.sub_id))
folder = folder.replace('\\', '/')
for f in files:
self.set_progress('Syncing {} to Google Drive'.format(os.path.join(root, f)), 0)
sickrage.app.api.google.upload(os.path.join(root, f), folder)
# removing deleted local folders/files from google drive
for drive_root, drive_folders, drive_files in self.walk_drive(folder_id):
for folder_id, folder_name in drive_folders.items():
if folder_name not in local_dirs:
sickrage.app.api.google.delete(folder_id)
for file_id, file_name in drive_files.items():
if file_name not in local_files:
sickrage.app.api.google.delete(file_id)
def sync_local(self):
main_folder = 'appDataFolder'
folder_id = sickrage.app.api.google.search_files(main_folder, sickrage.app.config.user.sub_id)['data']
for drive_root, drive_folders, drive_files in self.walk_drive(folder_id):
folder = drive_root.replace(folder_id, sickrage.app.data_dir)
folder = folder.replace('/', '\\')
for file_id, name in drive_files.items():
content = b64decode(sickrage.app.api.google.download(file_id)).strip()
================================================
FILE: sickrage/core/helpers/__init__.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import base64
import ctypes
import datetime
import glob
import hashlib
import ipaddress
import mimetypes
import os
import platform
import random
import re
import shutil
import socket
import stat
import string
import tempfile
import time
import traceback
import unicodedata
import uuid
import webbrowser
import zipfile
from collections import OrderedDict
from contextlib import contextmanager
from urllib.parse import uses_netloc, urlsplit, urlunsplit, urljoin
try:
# Python <= 3.9
from collections import Iterable
except ImportError:
# Python > 3.9
from collections.abc import Iterable
import errno
import rarfile
import requests
from bs4 import BeautifulSoup
import sickrage
from sickrage.core.enums import TorrentMethod
from sickrage.core.helpers import encryption
from sickrage.core.websession import WebSession
mimetypes.add_type('video/x-m4v', '.m4v')
mimetypes.add_type('video/x-matroska', '.mkv')
mimetypes.add_type('video/divx', '.divx')
mimetypes.add_type("video/x-flv", ".flv")
mimetypes.add_type("video/x-f4v", ".f4v")
mimetypes.add_type("video/x-dvd-iso", ".iso")
mimetypes.add_type("video/x-dvd-iso", ".img")
mimetypes.add_type("video/x-dvd-iso", ".nrg")
mimetypes.add_type("video/x-dvd-iso", ".ifo")
mimetypes.add_type("video/dvd", ".vob")
mimetypes.add_type("video/mpeg", ".wtv")
mimetypes.add_type("application/x-bittorrent", ".torrent")
mimetypes.add_type("application/x-nzb", ".nzb")
def safe_getattr(object, name, default=None):
try:
return getattr(object, name, default) or default
except:
return default
def try_int(value, default=0):
try:
return int(value)
except Exception:
return default
def read_file_buffered(filename, reverse=False):
blocksize = (1 << 15)
with open(filename, 'r', encoding='utf-8') as fh:
if reverse:
fh.seek(0, os.SEEK_END)
pos = fh.tell()
while True:
if reverse:
chunksize = min(blocksize, pos)
pos -= chunksize
else:
chunksize = max(blocksize, pos)
pos += chunksize
fh.seek(pos, os.SEEK_SET)
data = fh.read(chunksize)
if not data:
break
yield data
del data
def arg_to_bool(x):
"""
convert argument of unknown type to a bool:
"""
if isinstance(x, str):
if x.lower() in ("0", "false", "f", "no", "n", "off"):
return False
elif x.lower() in ("1", "true", "t", "yes", "y", "on"):
return True
raise ValueError("failed to cast as boolean")
return bool(x)
def auto_type(s):
for fn in (int, float, arg_to_bool):
try:
return fn(s)
except ValueError:
pass
return (s, '')[s.lower() == "none"]
def fix_glob(path):
path = re.sub(r'\[', '[[]', path)
return re.sub(r'(?>> replace_extension('foo.avi', 'mkv')
'foo.mkv'
>>> replace_extension('.vimrc', 'arglebargle')
'.vimrc'
>>> replace_extension('a.b.c', 'd')
'a.b.d'
>>> replace_extension('', 'a')
''
>>> replace_extension('foo.bar', '')
'foo.'
"""
sepFile = filename.rpartition(".")
if sepFile[0] == "":
return filename
else:
return sepFile[0] + "." + newExt
def is_torrent_or_nzb_file(filename):
"""
Check if the provided ``filename`` is a NZB file or a torrent file, based on its extension.
:param filename: The filename to check
:return: ``True`` if the ``filename`` is a NZB file or a torrent file, ``False`` otherwise
"""
if not isinstance(filename, str):
return False
return filename.rpartition('.')[2].lower() in ['nzb', 'torrent']
def is_sync_file(filename):
"""
Returns true if filename is a syncfile, indicating filesystem may be in flux
:param filename: Filename to check
:return: True if this file is a syncfile, False otherwise
"""
extension = filename.rpartition(".")[2].lower()
# if extension == '!sync' or extension == 'lftp-pget-status' or extension == 'part' or extension == 'bts':
syncfiles = sickrage.app.config.general.sync_files
if extension in syncfiles.split(",") or filename.startswith('.syncthing'):
return True
else:
return False
def is_media_file(filename):
"""
Check if named file may contain media
:param filename: Filename to check
:return: True if this is a known media file, False if not
"""
# ignore samples
if re.search(r'(^|[\W_])(?^(?P(?:(?!\.part\d+\.rar$).)*)\.(?:(?:part0*1\.)?rar)$)'
ret = re.search(archive_regex, filename) is not None
try:
if ret and os.path.exists(filename) and os.path.isfile(filename):
ret = rarfile.is_rarfile(filename)
except (IOError, OSError):
pass
return ret
def sanitize_file_name(name):
"""
>>> sanitize_file_name('a/b/c')
'a-b-c'
>>> sanitize_file_name('abc')
'abc'
>>> sanitize_file_name('a"b')
'ab'
>>> sanitize_file_name('.a.b..')
'a.b'
"""
# remove bad chars from the filename
name = re.sub(r'[\\/*]', '-', name)
name = re.sub(r'[:"<>|?]', '', name)
name = re.sub(r'\u2122', '', name) # Trade Mark Sign
# remove leading/trailing periods and spaces
name = name.strip(' .')
return name
def make_dir(path):
"""
Make a directory on the filesystem
:param path: directory to make
:return: True if success, False if failure
"""
if not os.path.isdir(path):
try:
os.makedirs(path)
sickrage.app.notification_providers['synoindex'].addFolder(path)
except OSError:
return False
return True
def list_media_files(path):
"""
Get a list of files possibly containing media in a path
:param path: Path to check for files
:return: list of files
"""
if not dir or not os.path.isdir(path):
return []
files = []
for curFile in os.listdir(path):
fullCurFile = os.path.join(path, curFile)
# if it's a folder do it recursively
if os.path.isdir(fullCurFile) and not curFile.startswith('.') and not curFile == 'Extras':
files += list_media_files(fullCurFile)
elif is_media_file(curFile):
files.append(fullCurFile)
return files
def copy_file(src_file, dest_file):
"""
Copy a file from source to destination
:param src_file: Path of source file
:param dest_file: Path of destination file
"""
try:
shutil.copyfile(src_file, dest_file)
except (OSError, PermissionError) as e:
if e.errno in [errno.ENOSPC, errno.EACCES]:
sickrage.app.log.warning(e)
else:
sickrage.app.log.error(e)
else:
try:
shutil.copymode(src_file, dest_file)
except OSError:
pass
def move_file(src_file, dest_file):
"""
Move a file from source to destination
:param src_file: Path of source file
:param dest_file: Path of destination file
"""
try:
shutil.move(src_file, dest_file)
fix_set_group_id(dest_file)
except OSError:
copy_file(src_file, dest_file)
os.unlink(src_file)
def link(src, dst):
"""
Create a file link from source to destination.
TODO: Make this unicode proof
:param src: Source file
:param dst: Destination file
"""
if os.name == 'nt':
if ctypes.windll.kernel32.CreateHardLinkW(ctypes.c_wchar_p(dst), ctypes.c_wchar_p(src), None) == 0:
raise ctypes.WinError()
else:
os.link(src, dst)
def hardlink_file(src_file, dest_file):
"""
Create a hard-link (inside filesystem link) between source and destination
:param src_file: Source file
:param dest_file: Destination file
"""
try:
link(src_file, dest_file)
fix_set_group_id(dest_file)
except OSError as e:
if e.errno == errno.EEXIST:
# File exists. Don't fallback to copy
sickrage.app.log.warning('Failed to create hardlink of {src} at {dest}. Error: {error!r}'.format(
**{'src': src_file, 'dest': dest_file, 'error': e}))
else:
sickrage.app.log.warning(
"Failed to create hardlink of {src} at {dest}. Error: {error!r}. Copying instead".format(
**{'src': src_file, 'dest': dest_file, 'error': e}))
copy_file(src_file, dest_file)
def symlink(src, dst):
"""
Create a soft/symlink between source and destination
:param src: Source file
:param dst: Destination file
"""
if os.name == 'nt':
if ctypes.windll.kernel32.CreateSymbolicLinkW(ctypes.c_wchar_p(dst), ctypes.c_wchar_p(src),
1 if os.path.isdir(src) else 0) in [0, 1280]:
raise ctypes.WinError()
else:
os.symlink(src, dst)
def move_and_symlink_file(src_file, dest_file):
"""
Move a file from source to destination, then create a symlink back from destination from source. If this fails, copy
the file from source to destination
:param src_file: Source file
:param dest_file: Destination file
"""
try:
shutil.move(src_file, dest_file)
fix_set_group_id(dest_file)
symlink(dest_file, src_file)
except OSError as e:
if e.errno == errno.EEXIST:
# File exists. Don't fallback to copy
sickrage.app.log.warning('Failed to create symlink of {src} at {dest}. Error: {error!r}'.format(
**{'src': src_file, 'dest': dest_file, 'error': e}))
else:
sickrage.app.log.warning(
"Failed to create symlink of {src} at {dest}. Error: {error!r}. Copying instead".format(
**{'src': src_file, 'dest': dest_file, 'error': e}))
copy_file(src_file, dest_file)
def make_dirs(path):
"""
Creates any folders that are missing and assigns them the permissions of their
parents
"""
sickrage.app.log.debug("Checking if the path [{}] already exists".format(path))
if not os.path.isdir(path):
# Windows, create all missing folders
if os.name == 'nt' or os.name == 'ce':
try:
sickrage.app.log.debug("Folder %s didn't exist, creating it" % path)
os.makedirs(path)
except (OSError, IOError) as e:
sickrage.app.log.warning("Failed creating %s : %r" % (path, e))
return False
# not Windows, create all missing folders and set permissions
else:
sofar = ''
folder_list = path.split(os.path.sep)
# look through each subfolder and make sure they all exist
for cur_folder in folder_list:
sofar += cur_folder + os.path.sep
# if it exists then just keep walking down the line
if os.path.isdir(sofar):
continue
try:
sickrage.app.log.debug("Folder %s didn't exist, creating it" % sofar)
os.mkdir(sofar)
# use normpath to remove end separator, otherwise checks permissions against itself
chmod_as_parent(os.path.normpath(sofar))
# do the library update for synoindex
sickrage.app.notification_providers['synoindex'].addFolder(sofar)
except (OSError, IOError) as e:
sickrage.app.log.error("Failed creating %s : %r" % (sofar, e))
return False
return True
def delete_empty_folders(check_empty_dir, keep_dir=None):
"""
Walks backwards up the path and deletes any empty folders found.
:param check_empty_dir: The path to clean (absolute path to a folder)
:param keep_dir: Clean until this path is reached
"""
# treat check_empty_dir as empty when it only contains these items
ignore_items = []
sickrage.app.log.info("Trying to clean any empty folders under " + check_empty_dir)
# as long as the folder exists and doesn't contain any files, delete it
try:
while os.path.isdir(check_empty_dir) and check_empty_dir != keep_dir:
check_files = os.listdir(check_empty_dir)
if not check_files or (len(check_files) <= len(ignore_items)
and all([check_file in ignore_items for check_file in check_files])):
try:
# directory is empty or contains only ignore_items
sickrage.app.log.info("Deleting empty folder: " + check_empty_dir)
shutil.rmtree(check_empty_dir)
# do the library update for synoindex
sickrage.app.notification_providers['synoindex'].deleteFolder(check_empty_dir)
except OSError as e:
sickrage.app.log.warning("Unable to delete %s. Error: %r" % (check_empty_dir, repr(e)))
raise StopIteration
check_empty_dir = os.path.dirname(check_empty_dir)
else:
raise StopIteration
except StopIteration:
pass
def file_bit_filter(mode):
"""
Strip special filesystem bits from file
:param mode: mode to check and strip
:return: required mode for media file
"""
for bit in [stat.S_IXUSR, stat.S_IXGRP, stat.S_IXOTH, stat.S_ISUID, stat.S_ISGID]:
if mode & bit:
mode -= bit
return mode
def chmod_as_parent(child_path):
"""
Retain permissions of parent for childs
(Does not work for Windows hosts)
:param child_path: Child Path to change permissions to sync from parent
"""
if os.name == 'nt' or os.name == 'ce':
return
parent_path = os.path.dirname(child_path)
if not parent_path:
sickrage.app.log.debug("No parent path provided in " + child_path + ", unable to get permissions from it")
return
child_path = os.path.join(parent_path, os.path.basename(child_path))
if not os.path.exists(child_path):
return
parent_path_stat = os.stat(parent_path)
parent_mode = stat.S_IMODE(parent_path_stat[stat.ST_MODE])
child_path_stat = os.stat(child_path)
child_path_mode = stat.S_IMODE(child_path_stat[stat.ST_MODE])
if os.path.isfile(child_path) and sickrage.app.config.general.strip_special_file_bits:
child_mode = file_bit_filter(parent_mode)
else:
child_mode = parent_mode
if child_path_mode == child_mode:
return
child_path_owner = child_path_stat.st_uid
user_id = os.geteuid()
if user_id not in (0, child_path_owner):
sickrage.app.log.debug("Not running as root or owner of " + child_path + ", not trying to set permissions")
return
try:
os.chmod(child_path, child_mode)
sickrage.app.log.debug(
"Setting permissions for %s to %o as parent directory has %o" % (child_path, child_mode, parent_mode))
except OSError:
sickrage.app.log.debug("Failed to set permission for %s to %o" % (child_path, child_mode))
def fix_set_group_id(child_path):
"""
Inherit SGID from parent
(does not work on Windows hosts)
:param child_path: Path to inherit SGID permissions from parent
"""
if os.name == 'nt' or os.name == 'ce':
return
parent_path = os.path.dirname(child_path)
parent_stat = os.stat(parent_path)
parent_mode = stat.S_IMODE(parent_stat[stat.ST_MODE])
child_path = os.path.join(parent_path, os.path.basename(child_path))
if parent_mode & stat.S_ISGID:
parent_gid = parent_stat[stat.ST_GID]
child_stat = os.stat(child_path)
child_gid = child_stat[stat.ST_GID]
if child_gid == parent_gid:
return
child_path_owner = child_stat.st_uid
user_id = os.geteuid()
if user_id not in (0, child_path_owner):
sickrage.app.log.debug(
"Not running as root or owner of {}, not trying to set the set-group-ID".format(child_path))
return
try:
os.chown(child_path, -1, parent_gid)
sickrage.app.log.debug("Respecting the set-group-ID bit on the parent directory for {}".format(child_path))
except OSError:
sickrage.app.log.error("Failed to respect the set-group-ID bit on the parent directory for {} (setting "
"group ID {})".format(child_path, parent_gid))
def sanitize_scene_name(name, anime=False):
"""
Takes a show name and returns the "scenified" version of it.
:param anime: Some show have a ' in their name(Kuroko's Basketball) and is needed for search.
:return: A string containing the scene version of the show name given.
"""
if not name:
return ''
bad_chars = ',:()!?\u2019'
if not anime:
bad_chars += "'"
# strip out any bad chars
for x in bad_chars:
name = name.replace(x, "")
# tidy up stuff that doesn't belong in scene names
name = name.replace("- ", ".").replace(" ", ".").replace("&", "and").replace('/', '.')
name = re.sub(r"\.\.*", ".", name)
if name.endswith('.'):
name = name[:-1]
return name
def anon_url(*url):
"""
Return a URL string consisting of the Anonymous redirect URL and an arbitrary number of values appended.
"""
url = ''.join(map(str, url))
# Handle URL's containing https or http, previously only handled http
uri_pattern = '^https?://'
unicode_uri_pattern = re.compile(uri_pattern, re.UNICODE)
if not re.search(unicode_uri_pattern, url):
url = 'http://' + url
return '{}{}'.format(sickrage.app.config.general.anon_redirect, url)
def full_sanitize_scene_name(name):
return re.sub('[. -]', ' ', sanitize_scene_name(name)).lower().lstrip()
def is_hidden_folder(folder):
"""
Returns True if folder is hidden.
On Linux based systems hidden folders start with . (dot)
:param folder: Full path of folder to check
"""
def is_hidden(filepath):
name = os.path.basename(os.path.abspath(filepath))
return name.startswith('.') or has_hidden_attribute(filepath)
def has_hidden_attribute(filepath):
try:
attrs = ctypes.windll.kernel32.GetFileAttributesW(filepath)
assert attrs != -1
result = bool(attrs & 2)
except (AttributeError, AssertionError):
result = False
return result
if os.path.isdir(folder):
if is_hidden(folder):
return True
return False
def file_size(fname):
return os.stat(fname).st_size
def real_path(path):
"""
Returns: the canonicalized absolute pathname. The resulting path will have no symbolic link, '/./' or '/../' components.
"""
return os.path.normpath(os.path.normcase(os.path.realpath(path)))
def extract_zipfile(archive, targetDir):
"""
Unzip a file to a directory
:param archive: The file name for the archive with a full path
"""
try:
if not os.path.exists(targetDir):
os.mkdir(targetDir)
zip_file = zipfile.ZipFile(archive, 'r', allowZip64=True)
for member in zip_file.namelist():
filename = os.path.basename(member)
# skip directories
if not filename:
continue
# copy file (taken from zipfile's extract)
source = zip_file.open(member)
target = open(os.path.join(targetDir, filename), "wb")
shutil.copyfileobj(source, target)
source.close()
target.close()
zip_file.close()
return True
except Exception as e:
sickrage.app.log.warning("Zip extraction error: %r " % repr(e))
return False
def create_zipfile(fileList, archive, arcname=None):
"""
Store the config file as a ZIP
:param fileList: List of files to store
:param archive: ZIP file name
:param arcname: Archive path
:return: True on success, False on failure
"""
try:
with zipfile.ZipFile(archive, 'w', zipfile.ZIP_DEFLATED, allowZip64=True) as z:
for f in list(set(fileList)):
z.write(f, os.path.relpath(f, arcname))
return True
except Exception as e:
sickrage.app.log.warning("Zip creation error: {} ".format(e))
return False
def restore_config_zip(archive, target_dir, restore_main_database=True, restore_config_database=True, restore_cache_database=True, restore_image_cache=True):
"""
Restores a backup ZIP file back in place
"""
if not os.path.isfile(archive):
return
try:
if not os.path.exists(target_dir):
os.mkdir(target_dir)
else:
def path_leaf(path):
head, tail = os.path.split(path)
return tail or os.path.basename(head)
bak_filename = f'{path_leaf(target_dir)}-{datetime.datetime.now().strftime("%Y%m%d_%H%M%S")}'
move_file(target_dir, os.path.join(os.path.dirname(target_dir), bak_filename))
with zipfile.ZipFile(archive, 'r', allowZip64=True) as zip_file:
for member in zip_file.namelist():
if not restore_main_database and member.split('/')[0] == 'main_db_backup.json':
continue
if not restore_config_database and member.split('/')[0] == 'config_db_backup.json':
continue
if not restore_cache_database and member.split('/')[0] == 'cache_db_backup.json':
continue
if not restore_image_cache and member.split('/')[0] == 'cache':
continue
zip_file.extract(member, target_dir)
return True
except Exception as e:
sickrage.app.log.warning("Zip extraction error: {}".format(e))
shutil.rmtree(target_dir)
def backup_app_data(backup_dir, backup_type='manual', backup_main_db=True, backup_config_db=True, backup_cache_db=True, backup_image_cache=True, keep_num=0):
source = []
if not os.path.exists(backup_dir):
os.mkdir(backup_dir)
if keep_num > 0:
for x in sorted(glob.glob(os.path.join(backup_dir, f'*{backup_type}*.zip')), key=os.path.getctime, reverse=True)[keep_num:]:
os.remove(x)
# databases
if backup_main_db:
backup_file = os.path.join(*[sickrage.app.data_dir, f'{sickrage.app.main_db.name}_db_backup.json'])
sickrage.app.main_db.backup(backup_file)
source += [backup_file]
if backup_config_db:
backup_file = os.path.join(*[sickrage.app.data_dir, f'{sickrage.app.config.db.name}_db_backup.json'])
sickrage.app.config.db.backup(backup_file)
source += [backup_file]
if backup_cache_db:
backup_file = os.path.join(*[sickrage.app.data_dir, f'{sickrage.app.cache_db.name}_db_backup.json'])
sickrage.app.cache_db.backup(backup_file)
source += [backup_file]
# cache folder
if backup_image_cache and sickrage.app.cache_dir:
for (path, dirs, files) in os.walk(sickrage.app.cache_dir, topdown=True):
for dirname in dirs:
if path == sickrage.app.cache_dir and dirname not in ['images']:
dirs.remove(dirname)
for filename in files:
source += [os.path.join(path, filename)]
# ZIP filename
target = os.path.join(backup_dir, f'sickrage-{backup_type}-{datetime.datetime.now().strftime("%Y%m%d%H%M%S")}.zip')
return create_zipfile(source, target, sickrage.app.data_dir)
def restore_app_data(src_dir, dst_dir):
try:
files_list = [
'main.db',
'main.db-shm',
'main.db-wal',
'config.db',
'cache.db',
'cache.db-shm',
'cache.db-wal',
'privatekey.pem',
os.path.basename(sickrage.app.config_file)
]
for filename in files_list:
src_file = os.path.join(src_dir, filename)
dst_file = os.path.join(dst_dir, filename)
bak_file = os.path.join(dst_dir, '{}_{}.bak'.format(filename, datetime.datetime.now().strftime('%Y%m%d_%H%M%S')))
if os.path.exists(src_file):
if os.path.isfile(dst_file):
move_file(dst_file, bak_file)
move_file(src_file, dst_file)
# database
for db in [sickrage.app.main_db, sickrage.app.config.db, sickrage.app.cache_db]:
backup_file = os.path.join(*[src_dir, '{}_db_backup.json'.format(db.name)])
if os.path.exists(backup_file):
db.restore(backup_file)
# cache
if os.path.exists(os.path.join(src_dir, 'cache')):
if os.path.exists(os.path.join(dst_dir, 'cache')):
move_file(os.path.join(dst_dir, 'cache'), os.path.join(dst_dir, '{}_{}.bak'.format('cache', datetime.datetime.now().strftime('%Y%m%d_%H%M%S'))))
move_file(os.path.join(src_dir, 'cache'), dst_dir)
return True
except Exception as e:
return False
def modify_file_timestamp(fname, atime=None):
"""
Change a file timestamp (change modification date)
:param fname: Filename to touch
:param atime: Specific access time (defaults to None)
:return: True on success, False on failure
"""
if atime and fname and os.path.isfile(fname):
os.utime(fname, (atime, atime))
return True
return False
def touch_file(fname):
with open(fname, 'a'):
os.utime(fname, None)
def get_size(start_path='.'):
"""
Find the total dir and filesize of a path
:param start_path: Path to recursively count size
:return: total filesize
"""
if not os.path.isdir(start_path):
return -1
total_size = 0
try:
for dirpath, __, filenames in os.walk(start_path):
for f in filenames:
fp = os.path.join(dirpath, f)
try:
total_size += os.path.getsize(fp)
except OSError as e:
sickrage.app.log.warning("Unable to get size for file %s Error: %r" % (fp, e))
sickrage.app.log.debug(traceback.format_exc())
except Exception as e:
pass
return total_size
def generate_api_key():
""" Return a new randomized API_KEY"""
from hashlib import md5
# Create some values to seed md5
t = str(time.time()).encode('utf-8')
r = str(random.random()).encode('utf-8')
# Create the md5 instance and give it the current time
m = md5(t)
# Update the md5 instance with the random variable
m.update(r)
# Return a hex digest of the md5, eg 49f68a5c8493ec2c0bf489821c21fc3b
return m.hexdigest()
def pretty_file_size(size, use_decimal=False, **kwargs):
"""
Return a human readable representation of the provided ``size``.
:param size: The size to convert
:param use_decimal: use decimal instead of binary prefixes (e.g. kilo = 1000 instead of 1024)
:keyword units: A list of unit names in ascending order.
Default units: ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
:return: The converted size
"""
try:
size = max(float(size), 0.)
except (ValueError, TypeError):
size = 0.
remaining_size = size
units = kwargs.pop('units', ['B', 'KB', 'MB', 'GB', 'TB', 'PB'])
block = 1024. if not use_decimal else 1000.
for unit in units:
if remaining_size < block:
return '{0:3.2f} {1}'.format(remaining_size, unit)
remaining_size /= block
return size
def remove_article(text=''):
"""Remove the english articles from a text string"""
return re.sub(r'(?i)^(?:(?:A(?!\s+to)n?)|The)\s(\w)', r'\1', text)
def generate_secret():
"""Generate a new secret"""
return base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes).decode()
def verify_freespace(src, dest, oldfile=None):
"""Check if the target system has enough free space to copy or move a file.
:param src: Source filename
:param dest: Destination path
:param oldfile: File to be replaced (defaults to None)
:return: True if there is enough space for the file,
False if there isn't. Also returns True if the OS doesn't support this option
"""
if not isinstance(oldfile, list):
oldfile = [oldfile]
sickrage.app.log.debug(u'Trying to determine free space on destination drive')
if not os.path.isfile(src):
sickrage.app.log.warning('A path to a file is required for the source.'
' {source} is not a file.', {'source': src})
return True
try:
diskfree = get_disk_space_usage(dest, False)
if not diskfree:
sickrage.app.log.warning('Unable to determine the free space on your OS.')
return True
except Exception:
sickrage.app.log.warning('Unable to determine free space, assuming there is '
'enough.')
return True
try:
neededspace = os.path.getsize(src)
except OSError as error:
sickrage.app.log.warning('Unable to determine needed space. Aborting.'
' Error: {msg}', {'msg': error})
return False
if oldfile:
for f in oldfile:
if os.path.isfile(f.location):
diskfree += os.path.getsize(f.location)
if diskfree > neededspace:
return True
else:
sickrage.app.log.warning(
'Not enough free space.'
' Needed: {0} bytes ({1}),'
' found: {2} bytes ({3})',
neededspace, pretty_file_size(neededspace),
diskfree, pretty_file_size(diskfree)
)
return False
def pretty_time_delta(seconds):
sign_string = '-' if seconds < 0 else ''
seconds = abs(int(seconds))
days, seconds = divmod(seconds, 86400)
hours, seconds = divmod(seconds, 3600)
minutes, seconds = divmod(seconds, 60)
time_delta = sign_string
if days > 0:
time_delta += ' %dd' % days
if hours > 0:
time_delta += ' %dh' % hours
if minutes > 0:
time_delta += ' %dm' % minutes
if seconds > 0:
time_delta += ' %ds' % seconds
return time_delta
def is_file_locked(checkfile, writeLockCheck=False):
"""
Checks to see if a file is locked. Performs three checks
1. Checks if the file even exists
2. Attempts to open the file for reading. This will determine if the file has a write lock.
Write locks occur when the file is being edited or copied to, e.g. a file copy destination
3. If the readLockCheck parameter is True, attempts to rename the file. If this fails the
file is open by some other process for reading. The file can be read, but not written to
or deleted.
:param checkfile: the file being checked
:param writeLockCheck: when true will check if the file is locked for writing (prevents move operations)
"""
checkfile = os.path.abspath(checkfile)
if not os.path.exists(checkfile):
return True
try:
with open(checkfile, 'rb'):
pass
except IOError:
return True
if writeLockCheck:
lockFile = checkfile + ".lckchk"
if os.path.exists(lockFile):
os.remove(lockFile)
try:
os.rename(checkfile, lockFile)
time.sleep(1)
os.rename(lockFile, checkfile)
except (OSError, IOError):
return True
return False
def get_disk_space_usage(disk_path=None, pretty=True):
"""Return the free space in human readable bytes for a given path or False if no path given.
:param disk_path: the filesystem path being checked
:param pretty: return as bytes if None
"""
if disk_path and os.path.exists(disk_path):
if platform.system() == 'Windows':
free_bytes = ctypes.c_ulonglong(0)
ctypes.windll.kernel32.GetDiskFreeSpaceExW(ctypes.c_wchar_p(disk_path), None, None,
ctypes.pointer(free_bytes))
return pretty_file_size(free_bytes.value) if pretty else free_bytes.value
else:
st = os.statvfs(disk_path)
file_size = st.f_bavail * st.f_frsize
return pretty_file_size(file_size) if pretty else file_size
else:
return False
def get_free_space(directories):
single = not isinstance(directories, (tuple, list))
if single:
directories = [directories]
free_space = {}
for folder in directories:
size = None
if os.path.isdir(folder):
if os.name == 'nt':
__, total, free = ctypes.c_ulonglong(), ctypes.c_ulonglong(), ctypes.c_ulonglong()
fun = ctypes.windll.kernel32.GetDiskFreeSpaceExW
ret = fun(folder, ctypes.byref(__), ctypes.byref(total), ctypes.byref(free))
if ret == 0: raise ctypes.WinError()
return [total.value, free.value]
else:
s = os.statvfs(folder)
size = [s.f_blocks * s.f_frsize / (1024 * 1024), (s.f_bavail * s.f_frsize) / (1024 * 1024)]
if single:
return size
free_space[folder] = size
return free_space
def restore_versioned_file(backup_file, version):
"""
Restore a file version to original state
:param backup_file: File to restore
:param version: Version of file to restore
:return: True on success, False on failure
"""
numTries = 0
new_file, __ = os.path.splitext(backup_file)
restore_file = '{}.v{}'.format(new_file, version)
if not os.path.isfile(new_file):
sickrage.app.log.debug("Not restoring, %s doesn't exist" % new_file)
return False
try:
sickrage.app.log.debug("Trying to backup %s to %s.r%s before restoring backup"
% (new_file, new_file, version))
move_file(new_file, new_file + '.' + 'r' + str(version))
except Exception as e:
sickrage.app.log.warning("Error while trying to backup file %s before proceeding with restore: %r"
% (restore_file, e))
return False
while not os.path.isfile(new_file):
if not os.path.isfile(restore_file):
sickrage.app.log.debug("Not restoring, %s doesn't exist" % restore_file)
break
try:
sickrage.app.log.debug("Trying to restore file %s to %s" % (restore_file, new_file))
shutil.copy(restore_file, new_file)
sickrage.app.log.debug("Restore done")
break
except Exception as e:
sickrage.app.log.warning("Error while trying to restore file %s. Error: %r" % (restore_file, e))
numTries += 1
time.sleep(1)
sickrage.app.log.debug("Trying again. Attempt #: %s" % numTries)
if numTries >= 10:
sickrage.app.log.warning("Unable to restore file %s to %s" % (restore_file, new_file))
return False
return True
def backup_versioned_file(old_file, version):
"""
Back up an old version of a file
:param old_file: Original file, to take a backup from
:param version: Version of file to store in backup
:return: True if success, False if failure
"""
numTries = 0
new_file = '{}.v{}'.format(old_file, version)
while not os.path.isfile(new_file):
if not os.path.isfile(old_file):
sickrage.app.log.debug("Not creating backup, %s doesn't exist" % old_file)
break
try:
sickrage.app.log.debug("Trying to back up %s to %s" % (old_file, new_file))
shutil.copyfile(old_file, new_file)
sickrage.app.log.debug("Backup completed: {}".format(new_file))
break
except Exception as e:
sickrage.app.log.warning("Error while trying to back up %s to %s : %r" % (old_file, new_file, e))
numTries += 1
time.sleep(1)
sickrage.app.log.debug("Trying to perform backup again.")
if numTries >= 10:
sickrage.app.log.error("Unable to back up %s to %s please do it manually." % (old_file, new_file))
return False
return True
@contextmanager
def bs4_parser(markup, features="html5lib", *args, **kwargs):
try:
_soup = BeautifulSoup(markup, features=features, *args, **kwargs)
except:
_soup = BeautifulSoup(markup, features="html.parser", *args, **kwargs)
try:
yield _soup
finally:
_soup.clear(True)
def get_file_size(file):
try:
return os.path.getsize(file) / 1024 / 1024
except:
return None
def get_temp_dir():
"""
Returns the [system temp dir]/sickrage-u501 or sickrage-myuser
"""
import getpass
if hasattr(os, 'getuid'):
uid = "u%d" % (os.getuid())
else:
# For Windows
try:
uid = getpass.getuser()
except ImportError:
return os.path.join(tempfile.gettempdir(), "sickrage")
return os.path.join(tempfile.gettempdir(), "sickrage-%s" % uid)
def scrub(obj):
if isinstance(obj, dict):
for k in obj.copy().keys():
scrub(obj[k])
del obj[k]
elif isinstance(obj, list):
for i in reversed(range(len(obj.copy()))):
scrub(obj[i])
del obj[i]
def convert_size(size, default=0, units=None):
if units is None:
units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
size_regex = re.compile(r'([\d+.]+)\s?({})?'.format('|'.join(units)), re.I)
try:
size, unit = float(size_regex.search(str(size)).group(1) or -1), size_regex.search(str(size)).group(2) or 'B'
except Exception:
return default
size *= 1024 ** units.index(unit.upper())
return max(int(size), 0)
def random_string(size=8, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice(chars) for __ in range(size))
def clean_url(url):
"""
Returns an cleaned url starting with a scheme and folder with trailing /
or an empty string
"""
uses_netloc.append('scgi')
if url and url.strip():
url = url.strip()
if '://' not in url:
url = '//' + url
scheme, netloc, path, query, fragment = urlsplit(url, 'http')
if not path:
path += '/'
cleaned_url = urlunsplit((scheme, netloc, path, query, fragment))
else:
cleaned_url = ''
return cleaned_url
def launch_browser(protocol=None, host=None, startport=None):
browserurl = '{}://{}:{}/home/'.format(protocol or 'http', host, startport or 8081)
try:
sickrage.app.log.info("Launching browser window")
try:
webbrowser.open(browserurl, 2, 1)
except webbrowser.Error:
webbrowser.open(browserurl, 1, 1)
except webbrowser.Error:
print("Unable to launch a browser")
def is_ip_private(ip):
if isinstance(ip, bytes):
ip = ip.decode()
return ipaddress.ip_address(ip).is_private
def is_ip_whitelisted(ip):
to_return = False
whitelisted_addresses = []
if sickrage.app.config.general.ip_whitelist_enabled:
whitelisted_addresses += sickrage.app.config.general.ip_whitelist.split(',')
if sickrage.app.config.general.ip_whitelist_localhost_enabled:
whitelisted_addresses += ['127.0.0.1', '::1']
for x in whitelisted_addresses:
try:
if ip == x:
to_return = True
elif ipaddress.ip_address(ip) in ipaddress.ip_network(x):
to_return = True
except (TypeError, AttributeError, ValueError):
continue
if whitelisted_addresses and not to_return:
sickrage.app.log.debug('IP address {} is not allowed to bypass web authentication, not found in whitelists'.format(ip))
return to_return
def validate_url(value):
"""
Return whether or not given value is a valid URL.
:param value: URL address string to validate
"""
regex = (
r'^[a-z]+://([^/:]+{tld}|([0-9]{{1,3}}\.)'
r'{{3}}[0-9]{{1,3}})(:[0-9]+)?(\/.*)?$'
)
return (True, False)[not re.compile(regex.format(tld=r'\.[a-z]{2,10}')).match(value)]
def torrent_webui_url(reset=False):
if not reset:
return sickrage.app.client_web_urls.get('torrent', '')
if not sickrage.app.config.general.use_torrents or \
not sickrage.app.config.torrent.host.lower().startswith('http') or \
sickrage.app.config.general.torrent_method == TorrentMethod.BLACKHOLE or sickrage.app.config.general.enable_https and \
not sickrage.app.config.torrent.host.lower().startswith('https'):
sickrage.app.client_web_urls['torrent'] = ''
return sickrage.app.client_web_urls['torrent']
torrent_ui_url = re.sub('localhost|127.0.0.1', sickrage.app.web_host or get_internal_ip(), sickrage.app.config.torrent.host or '', re.I)
def test_exists(url):
try:
h = requests.head(url)
return h.status_code != 404
except (requests.exceptions.ConnectionError, requests.exceptions.ConnectTimeout):
return False
if sickrage.app.config.general.torrent_method == TorrentMethod.UTORRENT:
torrent_ui_url = '/'.join(s.strip('/') for s in (torrent_ui_url, 'gui/'))
elif sickrage.app.config.general.torrent_method == TorrentMethod.DOWNLOAD_STATION:
if test_exists(urljoin(torrent_ui_url, 'download/')):
torrent_ui_url = urljoin(torrent_ui_url, 'download/')
sickrage.app.client_web_urls['torrent'] = ('', torrent_ui_url)[test_exists(torrent_ui_url)]
return sickrage.app.client_web_urls['torrent']
def checkbox_to_value(option, value_on=True, value_off=False):
"""
Turns checkbox option 'on' or 'true' to value_on (1)
any other value returns value_off (0)
"""
if isinstance(option, list):
option = option[-1]
if isinstance(option, str):
option = str(option).strip().lower()
if option in (True, 'on', 'true', value_on) or try_int(option) > 0:
return value_on
return value_off
def clean_host(host, default_port=None):
"""
Returns host or host:port or empty string from a given url or host
If no port is found and default_port is given use host:default_port
"""
host = host.strip()
if host:
match_host_port = re.search(r'(?:http.*://)?(?P[^:/]+).?(?P[0-9]*).*', host)
cleaned_host = match_host_port.group('host')
cleaned_port = match_host_port.group('port')
if cleaned_host:
if cleaned_port:
host = cleaned_host + ':' + cleaned_port
elif default_port:
host = cleaned_host + ':' + str(default_port)
else:
host = cleaned_host
else:
host = ''
return host
def clean_hosts(hosts, default_port=None):
"""
Returns list of cleaned hosts by Config.clean_host
:param hosts: list of hosts
:param default_port: default port to use
:return: list of cleaned hosts
"""
cleaned_hosts = []
for cur_host in [x.strip() for x in hosts.split(",")]:
if cur_host:
cleaned_host = clean_host(cur_host, default_port)
if cleaned_host:
cleaned_hosts.append(cleaned_host)
if cleaned_hosts:
cleaned_hosts = ",".join(cleaned_hosts)
else:
cleaned_hosts = ''
return cleaned_hosts
def glob_escape(pathname):
"""
Escape all special characters.
"""
MAGIC_CHECK = re.compile(r'([*?[])')
drive, pathname = os.path.splitdrive(pathname)
pathname = MAGIC_CHECK.sub(r'[\1]', pathname)
return drive + pathname
def convert_to_timedelta(time_val):
"""
Given a *time_val* (string) such as '5d', returns a `datetime.timedelta`
object representing the given value (e.g. `timedelta(days=5)`). Accepts the
following '' formats:
========= ============ =========================
Character Meaning Example
========= ============ =========================
(none) Milliseconds '500' -> 500 Milliseconds
s Seconds '60s' -> 60 Seconds
m Minutes '5m' -> 5 Minutes
h Hours '24h' -> 24 Hours
d Days '7d' -> 7 Days
M Months '2M' -> 2 Months
y Years '10y' -> 10 Years
========= ============ =========================
"""
try:
num = int(time_val)
return datetime.timedelta(milliseconds=num)
except ValueError:
pass
num = int(time_val[:-1])
if time_val.endswith('s'):
return datetime.timedelta(seconds=num)
elif time_val.endswith('m'):
return datetime.timedelta(minutes=num)
elif time_val.endswith('h'):
return datetime.timedelta(hours=num)
elif time_val.endswith('d'):
return datetime.timedelta(days=num)
elif time_val.endswith('M'):
return datetime.timedelta(days=(num * 30)) # Yeah this is approximate
elif time_val.endswith('y'):
return datetime.timedelta(days=(num * 365)) # Sorry, no leap year support
def total_seconds(td):
"""
Given a timedelta (*td*) return an integer representing the equivalent of
Python 2.7's :meth:`datetime.timdelta.total_seconds`.
"""
return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10 ** 6) / 10 ** 6
def episode_num(season=None, episode=None, **kwargs):
"""
Convert season and episode into string
:param season: Season number
:param episode: Episode Number
:keyword numbering: Absolute for absolute numbering
:returns: a string in s01e01 format or absolute numbering
"""
numbering = kwargs.pop('numbering', 'standard')
if numbering == 'standard':
if season is not None and episode:
return 'S{0:0>2}E{1:02}'.format(season, episode)
elif numbering == 'absolute':
if not (season and episode) and (season or episode):
return '{0:0>3}'.format(season or episode)
def strip_accents(name):
try:
name = unicodedata.normalize('NFKD', name).encode('ASCII', 'ignore')
except UnicodeDecodeError:
pass
if isinstance(name, bytes):
name = name.decode()
return name
def md5_file_hash(filename):
blocksize = 8192
hasher = hashlib.md5()
with open(filename, 'rb') as afile:
buf = afile.read(blocksize)
while len(buf) > 0:
hasher.update(buf)
buf = afile.read(blocksize)
return hasher.hexdigest()
def get_extension(filename):
__, file_extension = os.path.splitext(filename)
return file_extension
def get_external_ip():
"""Return external IP of system."""
resp = WebSession().get('https://api.ipify.org')
if not resp or not resp.text:
return ''
return resp.text
def get_internal_ip():
"""Return internal IP of system."""
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 1))
return s.getsockname()[0]
except Exception:
return socket.gethostbyname(socket.gethostname())
def get_ip_address(hostname):
return socket.gethostbyname(hostname)
def camelcase(s):
parts = iter(s.split("_"))
return next(parts) + "".join(i.title() for i in parts)
def convert_dict_keys_to_camelcase(d):
new = {}
for k, v in d.items():
if isinstance(v, dict):
v = convert_dict_keys_to_camelcase(v)
if isinstance(k, str):
new[camelcase(k)] = v
return new
def flatten(nested_list):
flat = []
for x in nested_list:
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
for sub_x in flatten(x):
flat.append(sub_x)
else:
flat.append(x)
return flat
================================================
FILE: sickrage/core/helpers/anidb.py
================================================
import adba
import sickrage
from adba import AniDBCommandTimeoutError
from sickrage.core.exceptions import AnidbAdbaConnectionException
def set_up_anidb_connection():
"""Connect to anidb."""
if not sickrage.app.config.anidb.enable:
sickrage.app.log.debug('Usage of AniDB disabled. Skipping')
return False
if not sickrage.app.config.anidb.username and not sickrage.app.config.anidb.password:
sickrage.app.log.debug('AniDB username and/or password are not set. Aborting anidb lookup.')
return False
if not sickrage.app.adba_connection:
try:
sickrage.app.adba_connection = adba.Connection(keepAlive=True)
except Exception as error:
sickrage.app.log.warning('AniDB exception msg: {0!r}'.format(error))
return False
try:
if not sickrage.app.adba_connection.authed():
sickrage.app.adba_connection.auth(sickrage.app.config.anidb.username, sickrage.app.config.anidb.password)
else:
return True
except Exception as error:
sickrage.app.log.warning('AniDB exception msg: {0!r}'.format(error))
return False
return sickrage.app.adba_connection.authed()
def get_release_groups_for_anime(series_name):
"""Get release groups for an anidb anime."""
groups = []
if set_up_anidb_connection():
try:
anime = adba.Anime(sickrage.app.adba_connection, name=series_name)
groups = anime.get_groups()
except Exception as error:
sickrage.app.log.warning('Unable to retrieve Fansub Groups from AniDB. Error: {}'.format(error))
raise AnidbAdbaConnectionException(error)
return groups
def get_short_group_name(release_group):
short_group_list = []
try:
group = sickrage.app.adba_connection.group(gname=release_group)
except AniDBCommandTimeoutError:
sickrage.app.log.debug('Timeout while loading group from AniDB. Trying next group')
except Exception:
sickrage.app.log.debug('Failed while loading group from AniDB. Trying next group')
else:
for line in group.datalines:
if line['shortname']:
short_group_list.append(line['shortname'])
else:
if release_group not in short_group_list:
short_group_list.append(release_group)
return short_group_list
def short_group_names(groups):
"""
Find AniDB short group names for release groups
:param groups: list of groups to find short group names for
:return: list of shortened group names
"""
groups = groups.split(",")
short_group_list = []
if set_up_anidb_connection():
for group_name in groups:
short_group_list += get_short_group_name(group_name) or [group_name]
else:
short_group_list = groups
return short_group_list
def get_anime_episode(file_path):
"""
Look up anidb properties for an episode
:param file_path: file to check
:return: episode object
"""
ep = None
if set_up_anidb_connection():
ep = adba.Episode(sickrage.app.adba_connection, filePath=file_path,
paramsF=[
"quality",
"anidb_file_name",
"crc32"
],
paramsA=[
"epno",
"english_name",
"short_name_list",
"other_name",
"synonym_list"
])
return ep
================================================
FILE: sickrage/core/helpers/browser.py
================================================
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
#
# This file is part of SiCKRAGE.
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
import os
from operator import itemgetter
import sickrage
def get_win_drives():
""" Return list of detected drives """
assert os.name == 'nt'
from ctypes import windll
drives = []
bitmask = windll.kernel32.GetLogicalDrives()
for letter in map(chr, range(ord('A'), ord('Z')+1)):
if bitmask & 1:
drives.append(letter)
bitmask >>= 1
return drives
def getFileList(path, includeFiles, fileTypes):
# prune out directories to protect the user from doing stupid things (already lower case the dir to reduce calls)
hide_list = ['boot', 'bootmgr', 'cache', 'config.msi', 'msocache', 'recovery', '$recycle.bin',
'recycler', 'system volume information', 'temporary internet files'] # windows specific
hide_list += ['.fseventd', '.spotlight', '.trashes', '.vol', 'cachedmessages', 'caches', 'trash'] # osx specific
hide_list += ['.git']
file_list = []
dir_list = []
for filename in os.listdir(path):
if filename.lower() in hide_list:
continue
full_filename = os.path.join(path, filename)
is_file = os.path.isfile(full_filename)
if not includeFiles and is_file:
continue
is_image = False
allowed_type = True
if is_file and fileTypes:
if 'images' in fileTypes:
is_image = filename.endswith(('jpg', 'jpeg', 'png', 'tiff', 'gif'))
allowed_type = filename.endswith(tuple(fileTypes)) or is_image
if not allowed_type:
continue
item_to_add = {
'name': filename,
'path': full_filename,
'isFile': is_file,
'isImage': is_image,
'isAllowed': allowed_type
}
if is_file:
file_list.append(item_to_add)
else:
dir_list.append(item_to_add)
# Sort folders first, alphabetically, case insensitive
dir_list.sort(key=lambda mbr: itemgetter('name')(mbr).lower())
file_list.sort(key=lambda mbr: itemgetter('name')(mbr).lower())
return dir_list + file_list
def foldersAtPath(path, includeParent=False, includeFiles=False, fileTypes=None):
"""
Returns a list of dictionaries with the folders contained at the given path.
Give the empty string as the path to list the contents of the root path
(under Unix this means "/", on Windows this will be a list of drive letters)
:param path: to list contents
:param includeParent: boolean, include parent dir in list as well
:param includeFiles: boolean, include files or only directories
:param fileTypes: list, file extensions to include, 'images' is an alias for image types
:return: list of folders/files
"""
fileTypes = fileTypes or []
# walk up the tree until we find a valid path
while path and not os.path.isdir(path):
if path == os.path.dirname(path):
path = ''
break
else:
path = os.path.dirname(path)
if path == '':
if os.name == 'nt':
entries = [{'currentPath': 'Root'}]
for letter in get_win_drives():
letter_path = letter + ':\\'
entries.append({'name': letter_path, 'path': letter_path})
return entries
else:
path = '/'
# fix up the path and find the parent
path = os.path.abspath(os.path.normpath(path))
parent_path = os.path.dirname(path)
# if we're at the root then the next step is the meta-node showing our drive letters
if path == parent_path and os.name == 'nt':
parent_path = ''
try:
file_list = getFileList(path, includeFiles, fileTypes)
except OSError as e:
sickrage.app.log.warning('Unable to open {}: {} / {}'.format(path, repr(e), str(e)))
file_list = getFileList(parent_path, includeFiles, fileTypes)
entries = [{'currentPath': path}]
if includeParent and parent_path != path:
entries.append({'name': '..', 'path': parent_path})
entries.extend(file_list)
return entries
================================================
FILE: sickrage/core/helpers/encryption.py
================================================
import base64
import os
import zlib
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.serialization import load_pem_private_key, load_pem_public_key
import sickrage
def initialize():
private_key_filename = os.path.join(sickrage.app.data_dir, 'privatekey.pem')
private_key = load_private_key(private_key_filename)
if not private_key:
save_private_key(private_key_filename, generate_private_key())
def generate_private_key():
return rsa.generate_private_key(
public_exponent=65537,
key_size=4096,
backend=default_backend()
)
def verify_public_key(public_key, private_key):
try:
decrypt_string(encrypt_string(b'sickrage', public_key), private_key) == b'sickrage'
except ValueError:
return False
return True
def load_public_key(filename):
if not os.path.exists(filename):
return
try:
with open(filename, 'rb') as fd:
public_key = load_pem_public_key(fd.read(), default_backend())
return public_key
except Exception:
return
def load_private_key(filename):
if not os.path.exists(filename):
return
try:
with open(filename, 'rb') as fd:
private_key = load_pem_private_key(fd.read(), None, default_backend())
return private_key
except Exception:
return
def save_public_key(filename, public_key):
pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
with open(filename, 'wb') as fd:
fd.write(pem)
def save_private_key(filename, private_key):
pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
with open(filename, 'wb') as fd:
fd.write(pem)
def encrypt_file(filename, public_key):
chunk_size = 245
offset = 0
end_loop = False
encrypted = b""
with open(filename, 'rb') as fd:
blob = zlib.compress(fd.read())
while not end_loop:
chunk = blob[offset:offset + chunk_size]
if len(chunk) % chunk_size != 0:
end_loop = True
chunk += b" " * (chunk_size - len(chunk))
encrypted += public_key.encrypt(
chunk,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
offset += chunk_size
with open(filename, 'wb') as fd:
fd.write(base64.b64encode(encrypted))
def decrypt_file(filename, private_key):
chunk_size = 512
offset = 0
decrypted = b""
with open(filename, 'rb') as fd:
encrypted_blob = base64.b64decode(fd.read())
while offset < len(encrypted_blob):
chunk = encrypted_blob[offset: offset + chunk_size]
decrypted += private_key.decrypt(
chunk,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
offset += chunk_size
with open(filename, 'wb') as fd:
fd.write(zlib.decompress(decrypted))
def encrypt_string(string, public_key):
chunk_size = 245
offset = 0
end_loop = False
encrypted = b""
blob = zlib.compress(string)
while not end_loop:
chunk = blob[offset:offset + chunk_size]
if len(chunk) % chunk_size != 0:
end_loop = True
chunk += b" " * (chunk_size - len(chunk))
encrypted += public_key.encrypt(
chunk,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
offset += chunk_size
return base64.b64encode(encrypted)
def decrypt_string(string, private_key):
chunk_size = 512
offset = 0
decrypted = b""
encrypted_blob = base64.b64decode(string)
while offset < len(encrypted_blob):
chunk = encrypted_blob[offset: offset + chunk_size]
decrypted += private_key.decrypt(
chunk,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
offset += chunk_size
return zlib.decompress(decrypted)
================================================
FILE: sickrage/core/helpers/metadata.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import re
import knowit
import sickrage
extensions = {
'tvshow': ['mkv', 'wmv', 'avi', 'mpg', 'mpeg', 'mp4', 'm2ts', 'iso', 'img', 'mdf', 'ts', 'm4v', 'flv'],
'tvshow_extra': ['mds'],
'dvd': ['vts_*', 'vob'],
'nfo': ['nfo', 'txt', 'tag'],
'subtitle': ['sub', 'srt', 'ssa', 'ass'],
'subtitle_extra': ['idx'],
'trailer': ['mov', 'mp4', 'flv']
}
codecs = {
'audio': ['DTS', 'AC3', 'AC3D', 'MP3'],
'video': ['x264', 'H264', 'x265', 'H265', 'DivX', 'Xvid']
}
file_sizes = { # in MB
'tvshow': {'min': 200},
'trailer': {'min': 2, 'max': 199},
'backdrop': {'min': 0, 'max': 5},
}
resolutions = {
'2160p': {'resolution_width': 3840, 'resolution_height': 2160, 'aspect': 1.78},
'1080p': {'resolution_width': 1920, 'resolution_height': 1080, 'aspect': 1.78},
'1080i': {'resolution_width': 1920, 'resolution_height': 1080, 'aspect': 1.78},
'720p': {'resolution_width': 1280, 'resolution_height': 720, 'aspect': 1.78},
'720i': {'resolution_width': 1280, 'resolution_height': 720, 'aspect': 1.78},
'480p': {'resolution_width': 640, 'resolution_height': 480, 'aspect': 1.33},
'480i': {'resolution_width': 640, 'resolution_height': 480, 'aspect': 1.33},
'default': {'resolution_width': 0, 'resolution_height': 0, 'aspect': 1},
}
def get_resolution(filename):
for key in resolutions:
if key in filename.lower() and key != 'default':
return resolutions[key]
return resolutions['default']
def get_file_metadata(filename):
try:
p = knowit.know(filename)
# Video codec
vc = ('H264' if p['video'][0]['codec'] == 'AVC1' else 'x265' if p['video'][0]['codec'] == 'HEVC' else
p['video'][0]['codec'])
# Audio codec
ac = p['audio'][0]['codec']
# Resolution
width = re.match(r'(\d+)', str(p['video'][0]['width']))
height = re.match(r'(\d+)', str(p['video'][0]['height']))
return {
'title': p.get('title', ""),
'video': vc,
'audio': ac,
'resolution_width': int(width.group(1)) if width else 0,
'resolution_height': int(height.group(1)) if height else 0,
'audio_channels': p['audio'][0]['channels'],
}
except Exception:
sickrage.app.log.debug('Failed to parse meta for {}'.format(filename))
return {}
================================================
FILE: sickrage/core/helpers/show_names.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import datetime
import fnmatch
import os
import re
from functools import partial
import sickrage
from sickrage.core.common import EpisodeStatus, countryList
from sickrage.core.enums import SearchFormat
from sickrage.core.helpers import sanitize_scene_name, strip_accents
from sickrage.core.tv.show.helpers import find_show
resultFilters = [
"sub(bed|ed|pack|s)",
"(dir|sub|nfo)fix",
"(?
# URL: https://sickrage.ca
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
#
# This file is part of SiCKRAGE.
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
import locale
import sickrage
from sickrage.core.enums import TimezoneDisplay
date_presets = (
'%Y-%m-%d',
'%a, %Y-%m-%d',
'%A, %Y-%m-%d',
'%y-%m-%d',
'%a, %y-%m-%d',
'%A, %y-%m-%d',
'%m/%d/%Y',
'%a, %m/%d/%Y',
'%A, %m/%d/%Y',
'%m/%d/%y',
'%a, %m/%d/%y',
'%A, %m/%d/%y',
'%m-%d-%Y',
'%a, %m-%d-%Y',
'%A, %m-%d-%Y',
'%m-%d-%y',
'%a, %m-%d-%y',
'%A, %m-%d-%y',
'%m.%d.%Y',
'%a, %m.%d.%Y',
'%A, %m.%d.%Y',
'%m.%d.%y',
'%a, %m.%d.%y',
'%A, %m.%d.%y',
'%d-%m-%Y',
'%a, %d-%m-%Y',
'%A, %d-%m-%Y',
'%d-%m-%y',
'%a, %d-%m-%y',
'%A, %d-%m-%y',
'%d/%m/%Y',
'%a, %d/%m/%Y',
'%A, %d/%m/%Y',
'%d/%m/%y',
'%a, %d/%m/%y',
'%A, %d/%m/%y',
'%d.%m.%Y',
'%a, %d.%m.%Y',
'%A, %d.%m.%Y',
'%d.%m.%y',
'%a, %d.%m.%y',
'%A, %d.%m.%y',
'%d. %b %Y',
'%a, %d. %b %Y',
'%A, %d. %b %Y',
'%d. %b %y',
'%a, %d. %b %y',
'%A, %d. %b %y',
'%d. %B %Y',
'%a, %d. %B %Y',
'%A, %d. %B %Y',
'%d. %B %y',
'%a, %d. %B %y',
'%A, %d. %B %y',
'%b %d, %Y',
'%a, %b %d, %Y',
'%A, %b %d, %Y',
'%B %d, %Y',
'%a, %B %d, %Y',
'%A, %B %d, %Y'
)
time_presets = ('%I:%M:%S %p', '%H:%M:%S')
class SRDateTime(object):
def __init__(self, dt, convert=False):
self.dt = dt
if convert and sickrage.app.config.gui.timezone_display == TimezoneDisplay.LOCAL:
try:
self.dt = dt.astimezone(sickrage.app.tz)
except Exception as e:
pass
self.has_locale = True
self.en_US_norm = locale.normalize('en_US.utf-8')
# display Time in SickRage Format
def srftime(self, show_seconds=False, t_preset=None):
"""
Display time in SR format
:param show_seconds: Boolean, show seconds
:param t_preset: Preset time format
:return: time string
"""
strt = ''
try:
locale.setlocale(locale.LC_TIME, '')
except Exception:
pass
try:
if self.has_locale:
locale.setlocale(locale.LC_TIME, locale.normalize(sickrage.app.config.gui.gui_lang))
except Exception:
try:
if self.has_locale:
locale.setlocale(locale.LC_TIME, self.en_US_norm)
except Exception:
self.has_locale = False
try:
if t_preset is not None:
strt = self.dt.strftime(t_preset)
elif show_seconds:
strt = self.dt.strftime(sickrage.app.config.gui.time_preset_w_seconds)
else:
strt = self.dt.strftime(sickrage.app.config.gui.time_preset)
finally:
try:
if self.has_locale:
locale.setlocale(locale.LC_TIME, '')
except Exception:
self.has_locale = False
return strt
# display Date in SickRage Format
def srfdate(self, d_preset=None):
"""
Display date in SR format
:param d_preset: Preset date format
:return: date string
"""
strd = ''
try:
locale.setlocale(locale.LC_TIME, '')
except Exception:
pass
try:
if self.has_locale:
locale.setlocale(locale.LC_TIME, locale.normalize(sickrage.app.config.gui.gui_lang))
except Exception:
try:
if self.has_locale:
locale.setlocale(locale.LC_TIME, self.en_US_norm)
except Exception:
self.has_locale = False
try:
if d_preset is not None:
strd = self.dt.strftime(d_preset)
else:
strd = self.dt.strftime(sickrage.app.config.gui.date_preset)
finally:
try:
locale.setlocale(locale.LC_TIME, '')
except Exception:
pass
return strd
# display Datetime in SickRage Format
def srfdatetime(self, show_seconds=False, d_preset=None, t_preset=None):
"""
Show datetime in SR format
:param show_seconds: Boolean, show seconds as well
:param d_preset: Preset date format
:param t_preset: Preset time format
:return: datetime string
"""
strd = ''
try:
locale.setlocale(locale.LC_TIME, '')
except Exception:
pass
try:
if d_preset is not None:
strd = self.dt.strftime(d_preset)
else:
strd = self.dt.strftime(sickrage.app.config.gui.date_preset)
try:
if self.has_locale:
locale.setlocale(locale.LC_TIME, locale.normalize(sickrage.app.config.gui.gui_lang))
except Exception:
try:
if self.has_locale:
locale.setlocale(locale.LC_TIME, self.en_US_norm)
except Exception:
self.has_locale = False
if t_preset is not None:
strd += ', {}'.format(self.dt.strftime(t_preset))
elif show_seconds:
strd += ', {}'.format(self.dt.strftime(sickrage.app.config.gui.time_preset_w_seconds))
else:
strd += ', {}'.format(self.dt.strftime(sickrage.app.config.gui.time_preset))
finally:
try:
if self.has_locale:
locale.setlocale(locale.LC_TIME, '')
except Exception:
self.has_locale = False
return strd
================================================
FILE: sickrage/core/imdb_popular.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import datetime
import os
import posixpath
import re
import sickrage
from sickrage.core.helpers import bs4_parser
from sickrage.core.websession import WebSession
class imdbPopular(object):
def __init__(self):
"""Gets a list of most popular TV series from imdb"""
# Use akas.imdb.com, just like the imdb lib.
self.url = 'http://www.imdb.com/search/title'
self.params = {
'at': 0,
'sort': 'moviemeter',
'title_type': 'tv_series',
'year': '%s,%s' % (datetime.date.today().year - 1, datetime.date.today().year + 1)
}
def fetch_popular_shows(self):
"""Get popular show information from IMDB"""
popular_shows = []
data = WebSession().get(self.url, headers={'Referer': 'http://www.imdb.com/'}, params=self.params)
if not data or not data.text:
sickrage.app.log.debug("No data returned from IMDb")
return
with bs4_parser(data.text) as soup:
for row in soup.find_all("div", {"class": "lister-item"}):
show = {}
image_div = row.find("div", {"class": "lister-item-image"})
if image_div:
image = image_div.find("img")
show['image_url_large'] = self.change_size(image['loadlate'], 3)
show['imdb_tt'] = image['data-tconst']
show['image_path'] = posixpath.join('images', 'imdb_popular',
os.path.basename(show['image_url_large']))
self.cache_image(show['image_url_large'])
content = row.find("div", {"class": "lister-item-content"})
if content:
header = row.find("h3", {"class": "lister-item-header"})
if header:
a_tag = header.find("a")
if a_tag:
show['name'] = a_tag.get_text(strip=True)
show['imdb_url'] = "http://www.imdb.com" + a_tag["href"]
show['year'] = header.find("span",
{"class": "lister-item-year"}).contents[0].split(" ")[0][1:5]
imdb_rating = row.find("div", {"class": "ratings-imdb-rating"})
show['rating'] = imdb_rating['data-value'] if imdb_rating else None
votes = row.find("span", {"name": "nv"})
show['votes'] = votes['data-value'] if votes else None
outline = content.find_all("p", {"class": "text-muted"})
if outline and len(outline) >= 2:
show['outline'] = outline[1].contents[0].strip("\"")
else:
show['outline'] = ''
popular_shows.append(show)
return popular_shows
@staticmethod
def change_size(image_url, factor=3):
match = re.search(r"^(.*)V1_(.{2})(.*?)_(.{2})(.*?),(.*?),(.*?),(.\d?)_(.*?)_.jpg$", image_url)
if match:
matches = match.groups()
os.path.basename(image_url)
matches = list(matches)
matches[2] = int(matches[2]) * factor
matches[4] = int(matches[4]) * factor
matches[5] = int(matches[5]) * factor
matches[6] = int(matches[6]) * factor
matches[7] = int(matches[7]) * factor
return "{}V1._{}{}_{}{},{},{},{}_.jpg".format(matches[0], matches[1], matches[2], matches[3], matches[4],
matches[5], matches[6], matches[7])
else:
return image_url
def cache_image(self, image_url):
"""
Store cache of image in cache dir
:param image_url: Source URL
"""
path = os.path.abspath(os.path.join(sickrage.app.cache_dir, 'images', 'imdb_popular'))
if not os.path.exists(path):
os.makedirs(path)
full_path = os.path.join(path, os.path.basename(image_url))
if not os.path.isfile(full_path):
WebSession().download(image_url, full_path)
================================================
FILE: sickrage/core/logger/__init__.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import logging
import os
import pkgutil
import re
import sys
from logging import FileHandler, CRITICAL, DEBUG, ERROR, INFO, WARNING
from logging.handlers import RotatingFileHandler
from unidecode import unidecode
import sickrage
from sickrage.core.classes import ErrorViewer, WarningViewer
from sickrage.core.helpers import make_dir
from sickrage.search_providers import SearchProviderType
class Logger(logging.getLoggerClass()):
logging.captureWarnings(True)
logging.getLogger().addHandler(logging.NullHandler())
def __init__(self, name="sickrage", consoleLogging=True, fileLogging=False, debugLogging=False, logFile=None, logSize=1048576, logNr=5):
super(Logger, self).__init__(name)
self.propagate = False
self.consoleLogging = consoleLogging
self.fileLogging = fileLogging
self.debugLogging = debugLogging
self.logFile = logFile
self.logSize = logSize
self.logNr = logNr
self.CRITICAL = CRITICAL
self.DEBUG = DEBUG
self.ERROR = ERROR
self.WARNING = WARNING
self.INFO = INFO
self.DB = 5
self.logLevels = {
'CRITICAL': self.CRITICAL,
'ERROR': self.ERROR,
'WARNING': self.WARNING,
'INFO': self.INFO,
'DEBUG': self.DEBUG,
'DB': 5
}
# list of allowed loggers
self.loggers = {'sickrage': self,
'tornado.general': logging.getLogger('tornado.general'),
'tornado.application': logging.getLogger('tornado.application'),
'apscheduler.executors': logging.getLogger('apscheduler.executors'),
'apscheduler.jobstores': logging.getLogger('apscheduler.jobstores'),
'apscheduler.scheduler': logging.getLogger('apscheduler.scheduler')}
# set custom level for database logging
logging.addLevelName(self.logLevels['DB'], 'DB')
self.setLevel(self.logLevels['DB'])
# viewers
self.warning_viewer = WarningViewer()
self.error_viewer = ErrorViewer()
# start logger
self.start()
@property
def censored_items(self):
try:
items = [
sickrage.app.config.user.password,
sickrage.app.config.sabnzbd.password,
sickrage.app.config.sabnzbd.apikey,
sickrage.app.config.nzbget.password,
sickrage.app.config.synology.password,
sickrage.app.config.torrent.password,
sickrage.app.config.kodi.password,
sickrage.app.config.plex.password,
sickrage.app.config.plex.server_token,
sickrage.app.config.emby.apikey,
sickrage.app.config.growl.password,
sickrage.app.config.freemobile.apikey,
sickrage.app.config.telegram.apikey,
sickrage.app.config.join_app.apikey,
sickrage.app.config.prowl.apikey,
sickrage.app.config.twitter.password,
sickrage.app.config.twilio.auth_token,
sickrage.app.config.boxcar2.access_token,
sickrage.app.config.pushover.apikey,
sickrage.app.config.nma.api_keys,
sickrage.app.config.pushalot.auth_token,
sickrage.app.config.pushbullet.api_key,
sickrage.app.config.email.password,
sickrage.app.config.subtitles.addic7ed_pass,
sickrage.app.config.subtitles.legendastv_pass,
sickrage.app.config.subtitles.itasa_pass,
sickrage.app.config.subtitles.opensubtitles_pass,
sickrage.app.config.anidb.password
]
for __, search_provider in sickrage.app.search_providers.all().items():
if search_provider.provider_type in [SearchProviderType.NZB, SearchProviderType.NEWZNAB]:
items.append(search_provider.api_key)
elif search_provider.provider_type == SearchProviderType.TORRENT_RSS and not search_provider.default:
items.append(search_provider.url)
items.append(search_provider.cookies)
[items.append(search_provider.custom_settings[item]) for item in [
'digest',
'hash',
'api_key',
'password',
'passkey',
'pin',
] if item in search_provider.custom_settings]
return list(filter(None, items))
except AttributeError:
return []
def start(self):
# remove all handlers
self.handlers.clear()
# console log handler
if self.consoleLogging:
console_handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s %(levelname)s::%(threadName)s::%(message)s', '%H:%M:%S')
console_handler.setFormatter(formatter)
console_handler.setLevel(self.logLevels['INFO'] if not self.debugLogging else self.logLevels['DEBUG'])
self.addHandler(console_handler)
# file log handlers
if self.logFile:
# make logs folder if it doesn't exist
if not os.path.exists(os.path.dirname(self.logFile)):
if not os.makedirs(os.path.dirname(self.logFile)):
return
if sickrage.app.developer:
rfh = FileHandler(
filename=self.logFile,
)
else:
rfh = RotatingFileHandler(
filename=self.logFile,
maxBytes=self.logSize,
backupCount=self.logNr
)
rfh_errors = RotatingFileHandler(
filename=self.logFile.replace('.log', '.error.log'),
maxBytes=self.logSize,
backupCount=self.logNr
)
formatter = logging.Formatter('%(asctime)s %(levelname)s::%(threadName)s::%(message)s', '%Y-%m-%d %H:%M:%S')
rfh.setFormatter(formatter)
rfh.setLevel(self.logLevels['INFO'] if not self.debugLogging else self.logLevels['DEBUG'])
self.addHandler(rfh)
rfh_errors.setFormatter(formatter)
rfh_errors.setLevel(self.logLevels['ERROR'])
self.addHandler(rfh_errors)
def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None):
if name in self.loggers:
record = super(Logger, self).makeRecord(name, level, fn, lno, msg, args, exc_info, func, extra, sinfo)
try:
def repl(m):
return '*' * len(m.group())
record.msg = re.sub(fr"\b({'|'.join(self.censored_items)})\b", repl, record.msg)
record.msg = unidecode(record.msg)
except:
pass
# sending record to UI
if record.levelno in [WARNING, ERROR]:
(self.warning_viewer, self.error_viewer)[record.levelno == ERROR].add("{}::{}".format(record.threadName, record.msg), True)
return record
def set_level(self):
self.debugLogging = sickrage.app.debug
level = DEBUG if self.debugLogging else INFO
for __, logger in self.loggers.items():
logger.setLevel(level)
for handler in logger.handlers:
if not handler.name == 'sentry':
handler.setLevel(level)
def list_modules(self, package):
"""Return all sub-modules for the specified package.
:param package:
:type package: module
:return:
:rtype: list of str
"""
return [modname for importer, modname, ispkg in pkgutil.walk_packages(path=package.__path__, prefix=package.__name__ + '.', onerror=lambda x: None)]
def get_loggers(self, package):
"""Return all loggers for package and sub-packages.
:param package:
:type package: module
:return:
:rtype: list of logging.Logger
"""
return [logging.getLogger(modname) for modname in self.list_modules(package)]
def log(self, level, msg, *args, **kwargs):
super(Logger, self).log(level, msg, *args, **kwargs)
def db(self, msg, *args, **kwargs):
super(Logger, self).log(self.logLevels['DB'], msg, *args, **kwargs)
def info(self, msg, *args, **kwargs):
super(Logger, self).info(msg, *args, **kwargs)
def debug(self, msg, *args, **kwargs):
super(Logger, self).debug(msg, *args, **kwargs)
def critical(self, msg, *args, **kwargs):
super(Logger, self).critical(msg, *args, **kwargs)
def exception(self, msg, *args, **kwargs):
super(Logger, self).exception(msg, *args, **kwargs)
def error(self, msg, *args, **kwargs):
kwargs['exc_info'] = True
super(Logger, self).error(msg, *args, **kwargs)
def warning(self, msg, *args, **kwargs):
super(Logger, self).warning(msg, *args, **kwargs)
def fatal(self, msg, *args, **kwargs):
super(Logger, self).fatal(msg, *args, **kwargs)
sys.exit(1)
def close(self, *args, **kwargs):
logging.shutdown()
================================================
FILE: sickrage/core/media/__init__.py
================================================
import os
from mimetypes import guess_type
from tornado.escape import url_escape
import sickrage
from sickrage.core.exceptions import MultipleShowObjectsException
from sickrage.core.tv.show.helpers import find_show
class Media(object):
def __init__(self, series_id, episode_id=None, series_provider_id=None, media_format=None):
"""
:param series_id: The series id of the show
:param media_format: The media format of the show image
"""
self.media_format = media_format
if not self.media_format:
self.media_format = 'normal'
try:
self.series_id = int(series_id)
except ValueError:
self.series_id = 0
self.episode_id = episode_id
self.series_provider_id = series_provider_id
def get_default_media_name(self):
"""
:return: The name of the file to use as a fallback if the show media file is missing
"""
return ''
@property
def url(self):
"""
:return: The url to the desired media file
"""
path = self.get_static_media_path().replace(sickrage.app.cache_dir, "")
path = path.replace(sickrage.app.gui_static_dir, "")
return url_escape(path.replace('\\', '/'), False)
@property
def content(self):
"""
:return: The content of the desired media file
"""
with open(os.path.abspath(self.get_static_media_path()).replace('\\', '/'), 'rb') as media:
return media.read()
@property
def type(self):
"""
:return: The mime type of the current media
"""
static_media_path = self.get_static_media_path()
if os.path.isfile(static_media_path):
return guess_type(static_media_path)[0]
return ''
def get_media_path(self):
"""
:return: The path to the media related to ``self.series_id``
"""
return ''
@staticmethod
def get_media_root():
"""
:return: The root folder containing the media
"""
return os.path.join(sickrage.app.gui_static_dir)
def get_show(self):
"""
:return: The show object associated with ``self.series_id`` or ``None``
"""
try:
return find_show(self.series_id, self.series_provider_id)
except MultipleShowObjectsException:
return None
def get_static_media_path(self):
"""
:return: The full path to the media
"""
return os.path.normpath(self.get_media_path())
================================================
FILE: sickrage/core/media/banner.py
================================================
# This file is part of SiCKRAGE.
#
# URL: https://www.sickrage.ca
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
import os
from sickrage.core.caches.image_cache import ImageCache
from sickrage.core.media import Media
class Banner(Media):
"""
Get the banner of a show
"""
def __init__(self, series_id, series_provider_id, media_format=None):
super(Banner, self).__init__(series_id, series_provider_id=series_provider_id, media_format=media_format)
def get_default_media_name(self):
return 'banner-thumb.png' if self.media_format == 'thumb' else 'banner.png'
def get_media_path(self):
media_file = ''
if self.media_format == 'normal':
media_file = ImageCache().banner_path(self.series_id)
if self.media_format == 'thumb':
media_file = ImageCache().banner_thumb_path(self.series_id)
if not all([media_file, os.path.exists(media_file)]):
media_file = os.path.join(self.get_media_root(), 'images', self.get_default_media_name())
return media_file
================================================
FILE: sickrage/core/media/fanart.py
================================================
# This file is part of SiCKRAGE.
#
# URL: https://www.sickrage.ca
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
import os
from sickrage.core.caches.image_cache import ImageCache
from sickrage.core.media import Media
class FanArt(Media):
"""
Get the fan art of a show
"""
def __init__(self, series_id, series_provider_id, media_format=None):
super(FanArt, self).__init__(series_id, series_provider_id=series_provider_id, media_format=media_format)
def get_default_media_name(self):
return 'fanart.png'
def get_media_path(self):
media_file = ''
if self.media_format == 'normal':
media_file = ImageCache().fanart_path(self.series_id)
if self.media_format == 'thumb':
media_file = ImageCache().fanart_thumb_path(self.series_id)
if not all([media_file, os.path.exists(media_file)]):
media_file = os.path.join(self.get_media_root(), 'images', self.get_default_media_name())
return media_file
================================================
FILE: sickrage/core/media/network.py
================================================
# This file is part of SiCKRAGE.
#
# URL: https://www.sickrage.ca
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
import os
from sickrage.core.media import Media
class Network(Media):
"""
Get the network logo of a show
"""
def __init__(self, series_id, series_provider_id, media_format=None):
super(Network, self).__init__(series_id, series_provider_id=series_provider_id, media_format=media_format)
def get_default_media_name(self):
return os.path.join('network', 'nonetwork.png')
def get_media_path(self):
media_file = ''
show = self.get_show()
if show:
media_file = os.path.join(self.get_media_root(), 'images', 'network', show.network_logo_name + '.png')
if not all([media_file, os.path.exists(media_file)]):
media_file = os.path.join(self.get_media_root(), 'images', self.get_default_media_name())
return media_file
================================================
FILE: sickrage/core/media/poster.py
================================================
# This file is part of SiCKRAGE.
#
# URL: https://www.sickrage.ca
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
import os
from sickrage.core.caches.image_cache import ImageCache
from sickrage.core.media import Media
class Poster(Media):
"""
Get the poster of a show
"""
def __init__(self, series_id, episode_id=None, series_provider_id=None, media_format='normal'):
super(Poster, self).__init__(series_id, episode_id, series_provider_id, media_format)
def get_default_media_name(self):
return 'poster-thumb.png' if self.media_format == 'thumb' else 'poster.png'
def get_media_path(self):
media_file = ''
if self.media_format == 'normal':
media_file = ImageCache().poster_path(self.series_id, episode_id=self.episode_id)
if self.media_format == 'thumb':
media_file = ImageCache().poster_thumb_path(self.series_id, episode_id=self.episode_id)
if not all([media_file, os.path.exists(media_file)]):
media_file = os.path.join(self.get_media_root(), 'images', self.get_default_media_name())
return media_file
================================================
FILE: sickrage/core/media/util.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import enum
import os
import sickrage
from sickrage.core.caches.image_cache import ImageCache
from sickrage.core.enums import SeriesProviderID
from sickrage.core.media.banner import Banner
from sickrage.core.media.fanart import FanArt
from sickrage.core.media.network import Network
from sickrage.core.media.poster import Poster
from sickrage.core.websession import WebSession
class SeriesImageType(enum.Enum):
BANNER = 'banner'
POSTER = 'poster'
FANART = 'fanart'
NETWORK = 'network'
SMALL = 'small'
BANNER_THUMB = 'banner_thumb'
POSTER_THUMB = 'poster_thumb'
def series_image(series_id=None, series_provider_id=None, which=None):
media_format = ('normal', 'thumb')[which in (SeriesImageType.BANNER_THUMB, SeriesImageType.POSTER_THUMB, SeriesImageType.SMALL)]
if which in (SeriesImageType.BANNER, SeriesImageType.BANNER_THUMB):
return Banner(series_id, series_provider_id, media_format)
elif which == SeriesImageType.FANART:
return FanArt(series_id, series_provider_id, media_format)
elif which in (SeriesImageType.POSTER, SeriesImageType.POSTER_THUMB):
return Poster(series_id, episode_id=None, series_provider_id=series_provider_id, media_format=media_format)
elif which == SeriesImageType.NETWORK:
return Network(series_id, series_provider_id, media_format)
def episode_image(series_id, episode_id, series_provider_id=None):
return Poster(series_id, episode_id=episode_id, series_provider_id=series_provider_id)
def series_provider_image(series_id=None, episode_id=None, series_provider_id=None, which=None):
media_format = ('normal', 'thumb')[which in (SeriesImageType.BANNER_THUMB, SeriesImageType.POSTER_THUMB, SeriesImageType.SMALL)]
if which not in (SeriesImageType.FANART, SeriesImageType.POSTER, SeriesImageType.BANNER, SeriesImageType.BANNER_THUMB, SeriesImageType.POSTER_THUMB):
sickrage.app.log.error(f"Invalid image type {which}, couldn't find it in the {sickrage.app.series_providers[SeriesProviderID.THETVDB].name} object")
return
try:
image_name = str(id) + '.' + which.value + '.jpg'
if media_format == "thumb":
image_path = os.path.join(ImageCache()._thumbnails_dir(), image_name)
if not os.path.exists(image_path):
image_data = sickrage.app.series_providers[series_provider_id].images(int(series_id), key_type=which.value)
if image_data:
image_url = image_data[0]['thumbnail']
WebSession().download(image_url, image_path)
else:
image_path = os.path.join(ImageCache()._cache_dir(), image_name)
if not os.path.exists(image_path):
image_data = sickrage.app.series_providers[series_provider_id].images(int(series_id), key_type=which.value)
if image_data:
image_url = image_data[0]['filename']
WebSession().download(image_url, image_path)
except (KeyError, IndexError):
pass
if which in [SeriesImageType.BANNER, SeriesImageType.BANNER_THUMB]:
return Banner(int(series_id), series_provider_id, media_format)
elif which == SeriesImageType.FANART:
return FanArt(int(series_id), series_provider_id, media_format)
elif which in [SeriesImageType.POSTER, SeriesImageType.POSTER_THUMB]:
return Poster(int(series_id), episode_id, series_provider_id, media_format)
================================================
FILE: sickrage/core/nameparser/__init__.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import os
import re
import time
from collections import OrderedDict
from threading import Lock
from dateutil import parser
from sqlalchemy import orm
import sickrage
from sickrage.core.common import Quality, Qualities
from sickrage.core.databases.main import MainDB
from sickrage.core.enums import SeriesProviderID
from sickrage.core.helpers import remove_extension, strip_accents
from sickrage.core.nameparser import regexes
from sickrage.core.scene_numbering import get_absolute_number_from_season_and_episode, get_series_provider_absolute_numbering, get_series_provider_numbering
from sickrage.core.tv.show.helpers import find_show_by_name, find_show, find_show_by_scene_exception
from sickrage.series_providers.helpers import search_series_provider_for_series_id
class NameParser(object):
ALL_REGEX = 0
NORMAL_REGEX = 1
ANIME_REGEX = 2
def __init__(self, file_name=True, series_id=None, series_provider_id=None, naming_pattern=False, validate_show=True):
self.file_name = file_name
self.show_obj = find_show(series_id, series_provider_id) if series_id and series_provider_id else None
self.naming_pattern = naming_pattern
self.validate_show = validate_show
if self.show_obj and not self.show_obj.is_anime:
self._compile_regexes(self.NORMAL_REGEX)
elif self.show_obj and self.show_obj.is_anime:
self._compile_regexes(self.ANIME_REGEX)
else:
self._compile_regexes(self.ALL_REGEX)
def get_show(self, name):
if not name:
return None
def series_provider_lookup(term):
for _series_provider_id in SeriesProviderID:
result = search_series_provider_for_series_id(term, _series_provider_id)
if result:
return result, _series_provider_id
return None, None
def scene_exception_lookup(term):
tv_show = find_show_by_scene_exception(term)
if tv_show:
return tv_show.series_id, tv_show.series_provider_id
return None, None
def show_cache_lookup(term):
tv_show = find_show_by_name(term)
if tv_show:
return tv_show.series_id, tv_show.series_provider_id
return None, None
for lookup in [show_cache_lookup, scene_exception_lookup, series_provider_lookup]:
for show_name in list({name, strip_accents(name), strip_accents(name).replace("'", " ")}):
try:
series_id, series_provider_id = lookup(show_name)
if not series_id or not series_provider_id:
continue
if self.validate_show and not find_show(series_id, series_provider_id):
continue
if series_id and series_provider_id:
return series_id, series_provider_id
except Exception as e:
sickrage.app.log.debug('SiCKRAGE encountered a error when attempting to lookup a series id by show name, Error: {!r}'.format(e))
@staticmethod
def clean_series_name(series_name):
"""Cleans up series name by removing any . and _
characters, along with any trailing hyphens.
Is basically equivalent to replacing all _ and . with a
space, but handles decimal numbers in string, for example:
"""
series_name = re.sub(r"(\D)\.(?!\s)(\D)", "\\1 \\2", series_name)
series_name = re.sub(r"(\d)\.(\d{4})", "\\1 \\2", series_name) # if it ends in a year then don't keep the dot
series_name = re.sub(r"(\D)\.(?!\s)", "\\1 ", series_name)
series_name = re.sub(r"\.(?!\s)(\D)", " \\1", series_name)
series_name = series_name.replace("_", " ")
series_name = re.sub(r"-$", "", series_name)
series_name = re.sub(r"^\[.*\]", "", series_name)
return series_name.strip()
def _compile_regexes(self, regexMode):
if regexMode == self.ANIME_REGEX:
dbg_str = "ANIME"
uncompiled_regex = [regexes.anime_regexes]
elif regexMode == self.NORMAL_REGEX:
dbg_str = "NORMAL"
uncompiled_regex = [regexes.normal_regexes]
else:
dbg_str = "ALL"
uncompiled_regex = [regexes.normal_regexes, regexes.anime_regexes]
self.compiled_regexes = []
for regexItem in uncompiled_regex:
for cur_pattern_num, (cur_pattern_name, cur_pattern) in enumerate(regexItem):
try:
cur_regex = re.compile(cur_pattern, re.VERBOSE | re.IGNORECASE)
except re.error as errormsg:
sickrage.app.log.info(
"WARNING: Invalid episode_pattern using %s regexs, %s. %s" % (
dbg_str, errormsg, cur_pattern))
else:
self.compiled_regexes.append((cur_pattern_num, cur_pattern_name, cur_regex))
def _parse_string(self, name, skip_scene_detection=False):
if not name:
return
session = sickrage.app.main_db.session()
matches = []
best_result = None
for (cur_regex_num, cur_regex_name, cur_regex) in self.compiled_regexes:
match = cur_regex.match(name)
if not match:
continue
result = ParseResult(name)
result.which_regex = {cur_regex_name}
result.score = 0 - cur_regex_num
named_groups = match.groupdict().keys()
if 'series_name' in named_groups:
result.series_name = match.group('series_name')
if result.series_name:
result.series_name = self.clean_series_name(result.series_name)
if 'season_num' in named_groups:
tmp_season = int(match.group('season_num'))
if cur_regex_name == 'bare' and tmp_season in (19, 20):
continue
if cur_regex_name == 'fov' and tmp_season > 500:
continue
result.season_number = tmp_season
if 'ep_num' in named_groups:
ep_num = self._convert_number(match.group('ep_num'))
if 'extra_ep_num' in named_groups and match.group('extra_ep_num'):
tmp_episodes = list(range(ep_num, self._convert_number(match.group('extra_ep_num')) + 1))
# if len(tmp_episodes) > 6:
# continue
else:
tmp_episodes = [ep_num]
result.episode_numbers = tmp_episodes
if 'ep_ab_num' in named_groups:
ep_ab_num = self._convert_number(match.group('ep_ab_num'))
if 'extra_ab_ep_num' in named_groups and match.group('extra_ab_ep_num'):
result.ab_episode_numbers = list(range(ep_ab_num, self._convert_number(match.group('extra_ab_ep_num')) + 1))
else:
result.ab_episode_numbers = [ep_ab_num]
if 'air_date' in named_groups:
air_date = match.group('air_date')
try:
result.air_date = parser.parse(air_date, fuzzy=True).date()
result.score += cur_regex_num
except Exception:
continue
if 'extra_info' in named_groups:
tmp_extra_info = match.group('extra_info')
# Show.S04.Special or Show.S05.Part.2.Extras is almost certainly not every episode in the season
if tmp_extra_info and cur_regex_name == 'season_only' and re.search(
r'([. _-]|^)(special|extra)s?\w*([. _-]|$)', tmp_extra_info, re.I):
continue
result.extra_info = tmp_extra_info
if 'release_group' in named_groups:
result.release_group = match.group('release_group')
if 'version' in named_groups:
# assigns version to anime file if detected using anime regex. Non-anime regex receives -1
version = match.group('version')
if version:
result.version = version
else:
result.version = 1
else:
result.version = -1
result.score += len([x for x in result.__dict__ if getattr(result, x, None) is not None])
matches.append(result)
if len(matches):
# pick best match with highest score based on placement
best_result = max(sorted(matches, reverse=True, key=lambda x: x.which_regex), key=lambda x: x.score)
show_obj = None
best_result.series_id = self.show_obj.series_id if self.show_obj else 0
best_result.series_provider_id = self.show_obj.series_provider_id if self.show_obj else SeriesProviderID.THETVDB
if not self.naming_pattern:
# try and create a show object for this result
result = self.get_show(best_result.series_name)
if result and len(result) == 2:
best_result.series_id, best_result.series_provider_id = result
if best_result.series_id and best_result.series_provider_id:
show_obj = find_show(best_result.series_id, best_result.series_provider_id)
# if this is a naming pattern test or result doesn't have a show object then return best result
if not show_obj or self.naming_pattern:
return best_result
# get quality
best_result.quality = Quality.name_quality(name, show_obj.is_anime)
new_episode_numbers = []
new_season_numbers = []
new_absolute_numbers = []
# if we have an air-by-date show then get the real season/episode numbers
if best_result.is_air_by_date:
try:
dbData = session.query(MainDB.TVEpisode).filter_by(series_id=show_obj.series_id, series_provider_id=show_obj.series_provider_id,
airdate=best_result.air_date).one()
season_number = int(dbData.season)
episode_numbers = [int(dbData.episode)]
except (orm.exc.NoResultFound, orm.exc.MultipleResultsFound):
season_number = None
episode_numbers = []
if not season_number or not episode_numbers:
series_provider_language = show_obj.lang or sickrage.app.config.general.series_provider_default_language
series_info = show_obj.series_provider.get_series_info(show_obj.series_id, language=series_provider_language)
if series_info:
ep_obj = series_info.aired_on(best_result.air_date)
if not ep_obj:
if best_result.in_showlist:
sickrage.app.log.warning(f"Unable to find episode with date {best_result.air_date} for show {show_obj.name}, skipping")
episode_numbers = []
else:
season_number = int(ep_obj[0]["seasonNumber"])
episode_numbers = [int(ep_obj[0]["episodeNumber"])]
for epNo in episode_numbers:
s = season_number
e = epNo
if show_obj.scene and not skip_scene_detection:
(s, e) = get_series_provider_numbering(show_obj.series_id,
show_obj.series_provider_id,
season_number,
epNo)
if s != -1:
new_season_numbers.append(s)
if e != -1:
new_episode_numbers.append(e)
elif show_obj.is_anime and best_result.ab_episode_numbers:
for epAbsNo in best_result.ab_episode_numbers:
a = epAbsNo
if show_obj.scene:
scene_result = show_obj.get_scene_exception_by_name(best_result.series_name)
if scene_result:
a = get_series_provider_absolute_numbering(show_obj.series_id,
show_obj.series_provider_id, epAbsNo,
True, scene_result[1])
(s, e) = show_obj.get_all_episodes_from_absolute_number([a])
if a != -1:
new_absolute_numbers.append(a)
new_season_numbers.append(s)
new_episode_numbers.extend(e)
elif best_result.season_number and best_result.episode_numbers:
for epNo in best_result.episode_numbers:
s = best_result.season_number
e = epNo
if show_obj.scene and not skip_scene_detection:
(s, e) = get_series_provider_numbering(show_obj.series_id,
show_obj.series_provider_id,
best_result.season_number,
epNo)
if show_obj.is_anime:
a = get_absolute_number_from_season_and_episode(show_obj.series_id, show_obj.series_provider_id, s, e)
if a not in [-1, None]:
new_absolute_numbers.append(a)
if s != -1:
new_season_numbers.append(s)
if e != -1:
new_episode_numbers.append(e)
# need to do a quick sanity check here. It's possible that we now have episodes
# from more than one season (by tvdb numbering), and this is just too much
# for sickrage, so we'd need to flag it.
new_season_numbers = list(set(new_season_numbers)) # remove duplicates
if len(new_season_numbers) > 1:
raise InvalidNameException(
f"Scene numbering results episodes from seasons {new_season_numbers}, (i.e. more than one) and sickrage does not support this. Sorry.")
# I guess it's possible that we'd have duplicate episodes too, so lets
# eliminate them
new_episode_numbers = list(set(new_episode_numbers))
new_episode_numbers.sort()
# maybe even duplicate absolute numbers so why not do them as well
new_absolute_numbers = list(set(new_absolute_numbers))
new_absolute_numbers.sort()
if len(new_absolute_numbers):
best_result.ab_episode_numbers = new_absolute_numbers
if len(new_season_numbers) and len(new_episode_numbers):
best_result.episode_numbers = new_episode_numbers
best_result.season_number = new_season_numbers[0]
if show_obj.scene and not skip_scene_detection:
sickrage.app.log.debug(f"Scene converted parsed result {best_result.original_name} into {best_result}")
# CPU sleep
time.sleep(0.02)
return best_result
def _combine_results(self, first, second, attr):
# if the first doesn't exist then return the second or nothing
if not first:
if not second:
return None
else:
return getattr(second, attr)
# if the second doesn't exist then return the first
if not second:
return getattr(first, attr)
a = getattr(first, attr)
b = getattr(second, attr)
# if a is good use it
if a is not None or (isinstance(a, list) and a):
return a
# if not use b (if b isn't set it'll just be default)
else:
return b
@staticmethod
def _convert_number(org_number):
"""
Convert org_number into an integer
org_number: integer or representation of a number: string or unicode
Try force converting to int first, on error try converting from Roman numerals
returns integer or 0
"""
try:
# try forcing to int
if org_number:
number = int(org_number)
else:
number = 0
except Exception:
# on error try converting from Roman numerals
roman_to_int_map = (
('M', 1000), ('CM', 900), ('D', 500), ('CD', 400), ('C', 100),
('XC', 90), ('L', 50), ('XL', 40), ('X', 10),
('IX', 9), ('V', 5), ('IV', 4), ('I', 1)
)
roman_numeral = org_number.upper()
number = 0
index = 0
for numeral, integer in roman_to_int_map:
while roman_numeral[index:index + len(numeral)] == numeral:
number += integer
index += len(numeral)
return number
def parse(self, name, cache_result=True, skip_scene_detection=False):
if self.naming_pattern:
cache_result = False
cached = name_parser_cache.get(name)
if cached:
return cached
# break it into parts if there are any (dirname, file name, extension)
dir_name, file_name = os.path.split(name)
base_file_name = file_name
if self.file_name:
base_file_name = remove_extension(file_name)
# set up a result to use
final_result = ParseResult(name)
# try parsing the file name
file_name_result = self._parse_string(base_file_name, skip_scene_detection)
# use only the direct parent dir
dir_name = os.path.basename(dir_name)
# parse the dirname for extra info if needed
dir_name_result = self._parse_string(dir_name, skip_scene_detection)
# build the ParseResult object
final_result.air_date = self._combine_results(file_name_result, dir_name_result, 'air_date')
# anime absolute numbers
final_result.ab_episode_numbers = self._combine_results(file_name_result, dir_name_result, 'ab_episode_numbers')
# season and episode numbers
final_result.season_number = self._combine_results(file_name_result, dir_name_result, 'season_number')
final_result.episode_numbers = self._combine_results(file_name_result, dir_name_result, 'episode_numbers')
# if the dirname has a release group/show name I believe it over the filename
final_result.series_name = self._combine_results(dir_name_result, file_name_result, 'series_name')
final_result.extra_info = self._combine_results(dir_name_result, file_name_result, 'extra_info')
final_result.release_group = self._combine_results(dir_name_result, file_name_result, 'release_group')
final_result.version = self._combine_results(dir_name_result, file_name_result, 'version')
if final_result == file_name_result:
final_result.which_regex = file_name_result.which_regex
elif final_result == dir_name_result:
final_result.which_regex = dir_name_result.which_regex
else:
if file_name_result:
final_result.which_regex |= file_name_result.which_regex
if dir_name_result:
final_result.which_regex |= dir_name_result.which_regex
final_result.series_id = self._combine_results(file_name_result, dir_name_result, 'series_id')
final_result.series_provider_id = self._combine_results(file_name_result, dir_name_result, 'series_provider_id')
final_result.quality = self._combine_results(file_name_result, dir_name_result, 'quality')
if self.validate_show:
if not self.naming_pattern and (not final_result.series_id or not final_result.series_provider_id):
raise InvalidShowException("Unable to match {} to a show in your database. Parser result: {}".format(name, final_result))
# if there's no useful info in it then raise an exception
if final_result.season_number is None and not final_result.episode_numbers and final_result.air_date is None and not final_result.ab_episode_numbers and not final_result.series_name:
raise InvalidNameException("Unable to parse {} to a valid episode. Parser result: {}".format(name, final_result))
if cache_result and final_result.series_id and final_result.series_provider_id:
name_parser_cache.add(name, final_result)
sickrage.app.log.debug("Parsed {} into {}".format(name, final_result))
return final_result
class ParseResult(object):
def __init__(self,
original_name,
series_name=None,
season_number=None,
episode_numbers=None,
extra_info=None,
release_group=None,
air_date=None,
ab_episode_numbers=None,
series_id=None,
series_provider_id=None,
score=None,
quality=None,
version=None
):
self.original_name = original_name
self.series_name = series_name
self.season_number = season_number
self.episode_numbers = episode_numbers or []
self.ab_episode_numbers = ab_episode_numbers or []
self.quality = quality or Qualities.UNKNOWN
self.extra_info = extra_info
self.release_group = release_group
self.air_date = air_date
self.series_id = series_id or 0
self.series_provider_id = series_provider_id or SeriesProviderID.THETVDB
self.score = score
self.version = version
self.which_regex = set()
def __eq__(self, other):
return other and all([
self.__class__ == other.__class__,
self.series_name == other.series_name,
self.season_number == other.season_number,
self.episode_numbers == other.episode_numbers,
self.extra_info == other.extra_info,
self.release_group == other.release_group,
self.air_date == other.air_date,
self.ab_episode_numbers == other.ab_episode_numbers,
self.score == other.score,
self.quality == other.quality,
self.version == other.version
])
def __str__(self):
to_return = ""
if self.series_name is not None:
to_return += 'SHOW:[{}]'.format(self.series_name)
if self.season_number is not None:
to_return += ' SEASON:[{}]'.format(str(self.season_number).zfill(2))
if self.episode_numbers and len(self.episode_numbers):
to_return += ' EPISODE:[{}]'.format(','.join(str(x).zfill(2) for x in self.episode_numbers))
if self.is_air_by_date:
to_return += ' AIRDATE:[{}]'.format(self.air_date)
if self.ab_episode_numbers:
to_return += ' ABS:[{}]'.format(','.join(str(x).zfill(3) for x in self.ab_episode_numbers))
if self.version and self.is_anime is True:
to_return += ' ANIME VER:[{}]'.format(self.version)
if self.release_group:
to_return += ' GROUP:[{}]'.format(self.release_group)
to_return += ' ABD:[{}]'.format(self.is_air_by_date)
to_return += ' ANIME:[{}]'.format(self.is_anime)
to_return += ' REGEX:[{}]'.format(' '.join(self.which_regex))
return to_return
@property
def is_air_by_date(self):
if self.air_date:
return True
return False
@property
def is_anime(self):
if self.ab_episode_numbers:
return True
return False
@property
def in_showlist(self):
if find_show(self.series_id, self.series_provider_id):
return True
return False
class NameParserCache(object):
def __init__(self):
self.lock = Lock()
self.data = OrderedDict()
self.max_size = 200
def get(self, key):
with self.lock:
value = self.data.get(key)
if value:
sickrage.app.log.debug("Using cached parse result for: {}".format(key))
return value
def add(self, key, value):
with self.lock:
self.data.update({key: value})
while len(self.data) > self.max_size:
self.data.pop(list(self.data.keys())[0], None)
name_parser_cache = NameParserCache()
class InvalidNameException(Exception):
"""The given release name is not valid"""
class InvalidShowException(Exception):
"""The given show name is not valid"""
================================================
FILE: sickrage/core/nameparser/regexes.py
================================================
# -*- coding: utf-8 -*-
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
# all regexes are case insensitive
normal_regexes = [
('standard_repeat',
# Show.Name.S01E02.S01E03.Source.Quality.Etc-Group
# Show Name - S01E02 - S01E03 - S01E04 - Ep Name
r'''
^(?P.+?)[. _-]+ # Show_Name and separator
s(?P\d+)[. _-]* # S01 and optional separator
e(?P\d+) # E02 and separator
([. _-]+s(?P=season_num)[. _-]* # S01 and optional separator
e(?P\d+))+ # E03/etc and separator
[. _-]*((?P.+?) # Source_Quality_Etc-
((?[^ -]+([. _-]\[.*\])?))?)?$ # Group
'''),
('fov_repeat',
# Show.Name.1x02.1x03.Source.Quality.Etc-Group
# Show Name - 1x02 - 1x03 - 1x04 - Ep Name
r'''
^(?P.+?)[. _-]+ # Show_Name and separator
(?P\d+)x # 1x
(?P\d+) # 02 and separator
([. _-]+(?P=season_num)x # 1x
(?P\d+))+ # 03/etc and separator
[. _-]*((?P.+?) # Source_Quality_Etc-
((?[^ -]+([. _-]\[.*\])?))?)?$ # Group
'''),
('standard',
# Show.Name.S01E02.Source.Quality.Etc-Group
# Show Name - S01E02 - My Ep Name
# Show.Name.S01.E03.My.Ep.Name
# Show.Name.S01E02E03.Source.Quality.Etc-Group
# Show Name - S01E02-03 - My Ep Name
# Show.Name.S01.E02.E03
r'''
^((?P.+?)[. _-]+)? # Show_Name and separator
\(?s(?P\d+)[. _-]* # S01 and optional separator
e(?P\d+)\)? # E02 and separator
(([. _-]*e|-) # linking e/- char
(?P(?!(1080|720|480)[pi])\d+)(\))?)* # additional E03/etc
([. _,-]+((?P.+?) # Source_Quality_Etc-
((?[^ -]+([. _-]\[.*\])?))?)?)?$ # Group
'''),
('newpct',
# American Horror Story - Temporada 4 HDTV x264[Cap.408_409]SPANISH AUDIO -NEWPCT
# American Horror Story - Temporada 4 [HDTV][Cap.408][Espanol Castellano]
# American Horror Story - Temporada 4 HDTV x264[Cap.408]SPANISH AUDIO –NEWPCT)
r'''
(?P.+?).-.+\d{1,2}[ ,.] # Show name: American Horror Story
(?P.+)\[Cap\. # Quality: HDTV x264, [HDTV], HDTV x264
(?P\d{1,2}) # Season Number: 4
(?P\d{2}) # Episode Number: 08
((_\d{1,2}(?P\d{2})).*\]|.*\]) # Episode number2: 09
'''),
('mvgroup',
# BBC.Great.British.Railway.Journeys.Series4.03of25.Stoke-on-Trent.to.Winsford.720p.HDTV.x264.AAC.MVGroup
# BBC.Great.British.Railway.Journeys.Series.4.03of25.Stoke-on-Trent.to.Winsford.720p.HDTV.x264.AAC.MVGroup
# Tutankhamun.With.Dan.Snow.Series.1.Part.1.1080p.HDTV.x264.AAC.MVGroup.org.mp4
r'''
^(?P.+?)[. _-]+ # Show_Name and separator
series(?:[. _-]?)(?P\d+)[. _-]+ # Series.4
(?:part[. _-]+)?(?P\d{1,2})(?:of\d{1,2})? # 3of4
[. _-]+((?P.+?) # Source_Quality_Etc-
((?[^- ]+))?)?$
'''),
('fov',
# Show_Name.1x02.Source_Quality_Etc-Group
# Show Name - 1x02 - My Ep Name
# Show_Name.1x02x03x04.Source_Quality_Etc-Group
# Show Name - 1x02-03-04 - My Ep Name
r'''
^((?!\[.+?\])(?P.+?)[\[. _-]+)? # Show_Name and separator if no brackets group
(?P\d+)x # 1x
(?P\d+) # 02 and separator
(([. _-]*x|-) # linking x/- char
(?P # extra ep num
(?!(1080|720|480)[pi])(?!(?<=x)264) # ignore obviously wrong multi-eps
\d+))* # additional x03/etc
[\]. _-]*((?P.+?) # Source_Quality_Etc-
((?[^ -]+([. _-]\[.*\])?))?)?$ # Group
'''),
('scene_date_format',
# Show.Name.2010.11.23.Source.Quality.Etc-Group
# Show Name - 2010-11-23 - Ep Name
r'''
^((?P.+?)[. _-]+)? # Show_Name and separator
(?P\d{4}[. _-]\d{2}[. _-]\d{2}) # Air-date
[. _-]*((?P.+?) # Source_Quality_Etc-
((?[^ -]+([. _-]\[.*\])?))?)?$ # Group
'''),
('scene_sports_format',
# Show.Name.100.Event.2010.11.23.Source.Quality.Etc-Group
# Show.Name.2010.11.23.Source.Quality.Etc-Group
# Show Name - 2010-11-23 - Ep Name
r'''
^(?P.*?(UEFA|MLB|ESPN|WWE|MMA|UFC|TNA|EPL|NASCAR|NBA|NFL|NHL|NRL|PGA|SUPER LEAGUE|FORMULA|FIFA|NETBALL|MOTOGP).*?)[. _-]+
((?P\d{1,3})[. _-]+)?
(?P(\d+[. _-]\d+[. _-]\d+)|(\d+\w+[. _-]\w+[. _-]\d+))[. _-]+
((?P.+?)((?[^ -]+([. _-]\[.*\])?))?)?$
'''),
('stupid_with_denotative',
# aaf-sns03e09
# flhd-supernaturals07e02-1080p
r'''
(?P.+?)(?\w*)(?\d{1,2}) # s03
e(?P\d{2})(?:(rp|-(1080p|720p)))?$ # e09
'''),
('stupid',
# tpz-abc102
r'''
(?P.+?)(?\w*)(?\d{1,2}) # 1
(?P\d{2})$ # 02
'''),
('verbose',
# Show Name Season 1 Episode 2 Ep Name
r'''
^(?P.+?)[. _-]+ # Show Name and separator
(season|series)[. _-]+ # season and separator
(?P\d+)[. _-]+ # 1
episode[. _-]+ # episode and separator
(?P\d+)[. _-]+ # 02 and separator
(?P.+)$ # Source_Quality_Etc-
'''),
('season_only',
# Show.Name.S01.Source.Quality.Etc-Group
r'''
^((?P.+?)[. _-]+)? # Show_Name and separator
s(eason[. _-])? # S01/Season 01
(?P\d+)[. _-]* # S01 and optional separator
[. _-]*((?P.+?) # Source_Quality_Etc-
((?[^ -]+([. _-]\[.*\])?))?)?$ # Group
'''),
('no_season_multi_ep',
# Show.Name.E02-03
# Show.Name.E02.2010
r'''
^((?P.+?)[. _-]+)? # Show_Name and separator
(e(p(isode)?)?|part|pt)[. _-]? # e, ep, episode, or part
(?P(\d+|(?(?!(1080|720|480)[pi])(\d+|(?.+?) # Source_Quality_Etc-
((?[^ -]+([. _-]\[.*\])?))?)?$ # Group
'''),
('no_season_general',
# Show.Name.E23.Test
# Show.Name.Part.3.Source.Quality.Etc-Group
# Show.Name.Part.1.and.Part.2.Blah-Group
r'''
^((?P.+?)[. _-]+)? # Show_Name and separator
(e(p(isode)?)?|part|pt)[. _-]? # e, ep, episode, or part
(?P(\d+|((?(?!(1080|720|480)[pi])
(\d+|((?.+?) # Source_Quality_Etc-
((?[^ -]+([. _-]\[.*\])?))?)?$ # Group
'''),
('bare',
# Show.Name.102.Source.Quality.Etc-Group
r'''
^(?P.+?)[. _-]+ # Show_Name and separator
(?P\d{1,2}) # 1
(e?) # Optional episode separator
(?P\d{2}) # 02 and separator
([. _-]+(?P(?!\d{3}[. _-]+)[^-]+) # Source_Quality_Etc-
(-(?P[^ -]+([. _-]\[.*\])?))?)?$ # Group
'''),
('no_season',
# Show Name - 01 - Ep Name
# 01 - Ep Name
# 01 - Ep Name
r'''
^((?P.+?)(?:[. _-]{2,}|[. _]))? # Show_Name and separator
(?P\d{1,3}) # 02
(?:-(?P\d{1,3}))* # -03-04-05 etc
(\s*(?:of)?\s*\d{1,3})? # of joiner (with or without spaces) and series total ep
[. _-]+((?P.+?) # Source_Quality_Etc-
((?[^ -]+([. _-]\[.*\])?))?)?$ # Group
'''),
]
anime_regexes = [
('anime_horriblesubs',
# [HorribleSubs] Maria the Virgin Witch - 01 [720p].mkv
r'''
^(?:\[(?PHorribleSubs)\][\s\.])
(?:(?P.+?)[\s\.]-[\s\.])
(?P((?!(1080|720|480)[pi]))\d{1,3})
(-(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))?
(?:v(?P[0-9]))?
(?:[\w\.\s]*)
(?:(?:(?:[\[\(])(?P\d{3,4}[xp]?\d{0,4}[\.\w\s-]*)(?:[\]\)]))|(?:\d{3,4}[xp]))
.*?
'''),
('anime_erai-raws',
# [Erai-raws] Full Metal Panic! Invisible Victory - 12 END [1080p].mkv
# [Erai-raws] A.I.C.O. Incarnation - 01 [1080p][Multiple Subtitle].mkv
r'''
^(?:\[(?PErai-raws)\][\s\.])
(?:(?P.+?)[\s\.]-[\s\.])
(?P((?!(1080|720|480)[pi]))\d{1,3})
(-(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))?
(?:v(?P[0-9]))?
(?:[\w\.\s]*)
(?:(?:(?:[\[\(])(?P\d{3,4}[xp]?\d{0,4}[\.\w\s-]*)(?:[\]\)]))|(?:\d{3,4}[xp]))
(?:\[(?P.+?)?\])?
.*?
'''),
('anime_ultimate',
r'''
^(?:\[(?P.+?)\][ ._-]*)
(?P.+?)[ ._-]+
(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3})
(-(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))?[ ._-]+?
(?:v(?P[0-9]))?
(?:[\w\.]*)
(?:(?:(?:[\[\(])(?P\d{3,4}[xp]?\d{0,4}[\.\w\s-]*)(?:[\]\)]))|(?:\d{3,4}[xp]))
(?:[ ._]?\[(?P\w+)\])?
.*?
'''),
('anime_french_fansub',
# [Kaerizaki-Fansub]_One_Piece_727_[VOSTFR][HD_1280x720].mp4
# [Titania-Fansub]_Fairy_Tail_269_[VOSTFR]_[720p]_[1921E00C].mp4
# [ISLAND]One_Piece_726_[VOSTFR]_[V1]_[8bit]_[720p]_[2F7B3FA2].mp4
# Naruto Shippuden 445 VOSTFR par Fansub-Resistance (1280*720) - version MQ
# Dragon Ball Super 015 VOSTFR par Fansub-Resistance (1280x720) - HQ version
# [Mystic.Z-Team].Dragon.Ball.Super.-.épisode.36.VOSTFR.720p
# [Z-Team][DBSuper.pw] Dragon Ball Super - 028 (VOSTFR)(720p AAC)(MP4)
# [SnF] Shokugeki no Souma - 24 VOSTFR [720p][41761A60].mkv
# [Y-F] Ao no Kanata no Four Rhythm - 03 Vostfr HD 8bits
# Phantasy Star Online 2 - The Animation 04 vostfr FHD
# Detective Conan 804 vostfr HD
# Active Raid 04 vostfr [1080p]
# Sekko Boys 04 vostfr [720p]
r'''
^(\[(?P.+?)\][ ._-]*)? # Release Group and separator (Optional)
((\[|\().+?(\]|\))[ ._-]*)? # Extra info (Optionnal)
(?P.+?)[ ._-]+ # Show_Name and separator
((épisode|episode|Episode)[ ._-]+)? # Sentence for special fansub (Optionnal)
(?P\d{1,3})[ ._-]+ # Episode number and separator
(((\[|\())?(VOSTFR|vostfr|Vostfr|VostFR|vostFR)((\]|\)))?([ ._-])*)+ # Subtitle Language and separator
(par Fansub-Resistance)? # Sentence for special fansub (Optionnal)
(\[((v|V)(?P[0-9]))\]([ ._-])*)? # Version and separator (Optional)
((\[(8|10)(Bits|bits|Bit|bit)\])?([ ._-])*)? # Colour resolution and separator (Optional)
((\[|\()((FHD|HD|SD)*([ ._-])*((?P\d{3,4}[xp*]?\d{0,4}[\.\w\s-]*)))(\]|\)))? # Source_Quality_Etc-
([ ._-]*\[(?P\w{8})\])? # CRC (Optional)
.* # Separator and EOL
'''),
('anime_standard',
# [Group Name] Show Name.13-14
# [Group Name] Show Name - 13-14
# Show Name 13-14
# [Group Name] Show Name.13
# [Group Name] Show Name - 13
# Show Name 13
r'''
^(\[(?P.+?)\][ ._-]*)? # Release Group and separator
(?P.+?)[ ._-]+ # Show_Name and separator
(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}) # E01
(-(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # E02
(v(?P[0-9]))? # version
[ ._-]+\[(?P\d{3,4}[xp]?\d{0,4}[\.\w\s-]*)\] # Source_Quality_Etc-
(\[(?P\w{8})\])? # CRC
.*? # Separator and EOL
'''),
('anime_standard_round',
# [Stratos-Subs]_Infinite_Stratos_-_12_(1280x720_H.264_AAC)_[379759DB]
# [Stratos-Subs]_Infinite_Stratos_-_12_(1280x720_H.264_AAC) [379759DB]
# [ShinBunBu-Subs] Bleach - 02-03 (CX 1280x720 x264 AAC)
r'''
^(\[(?P.+?)\][ ._-]*)? # Release Group and separator
(?P.+?)[ ._-]+ # Show_Name and separator
(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}) # E01
(-(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # E02
(v(?P[0-9]))? # version
[ ._-]+\((?P(\w+[ ._-]?)?\d{3,4}[xp]?\d{0,4}[\.\w\s-]*)\)[ ._-]+ # Source_Quality_Etc-
(\[(?P\w{8})\])? # CRC
.*? # Separator and EOL
'''),
('anime_slash',
# [SGKK] Bleach 312v1 [720p/MKV]
r'''
^(\[(?P.+?)\][ ._-]*)? # Release Group and separator
(?P.+?)[ ._-]+ # Show_Name and separator
(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}) # E01
(-(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # E02
(v(?P[0-9]))? # version
[ ._-]+\[(?P\d{3,4}p) # Source_Quality_Etc-
(\[(?P\w{8})\])? # CRC
.*? # Separator and EOL
'''),
('anime_standard_codec',
# [Ayako]_Infinite_Stratos_-_IS_-_07_[H264][720p][EB7838FC]
# [Ayako] Infinite Stratos - IS - 07v2 [H264][720p][44419534]
# [Ayako-Shikkaku] Oniichan no Koto Nanka Zenzen Suki Janain Dakara ne - 10 [LQ][h264][720p] [8853B21C]
r'''
^(\[(?P.+?)\][ ._-]*)? # Release Group and separator
(?P.+?)[ ._]* # Show_Name and separator
([ ._-]+-[ ._-]+[A-Z]+[ ._-]+)?[ ._-]+ # funny stuff, this is sooo nuts ! this will kick me in the butt one day
(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}) # E01
(-(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # E02
(v(?P[0-9]))? # version
([ ._-](\[\w{1,2}\])?\[[a-z][.]?\w{2,4}\])? #codec
[ ._-]*\[(?P(\d{3,4}[xp]?\d{0,4})?[\.\w\s-]*)\] # Source_Quality_Etc-
(\[(?P\w{8})\])?
.*? # Separator and EOL
'''),
('anime_codec_crc',
r'''
^(?:\[(?P.*?)\][ ._-]*)?
(?:(?P.*?)[ ._-]*)?
(?:(?P(((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))[ ._-]*).+?
(?:\[(?P.*?)\][ ._-]*)
(?:\[(?P\w{8})\])?
.*?
'''),
('anime SxEE',
# Show_Name.1x02.Source_Quality_Etc-Group
# Show Name - 1x02 - My Ep Name
# Show_Name.1x02x03x04.Source_Quality_Etc-Group
# Show Name - 1x02-03-04 - My Ep Name
r'''
^((?!\[.+?\])(?P.+?)[\[. _-]+)? # Show_Name and separator if no brackets group
(?P\d+)x # 1x
(?P\d+) # 02 and separator
(([. _-]*x|-) # linking x/- char
(?P
(?!(1080|720|480)[pi])(?!(?<=x)264) # ignore obviously wrong multi-eps
\d+))* # additional x03/etc
[\]. _-]*((?P.+?) # Source_Quality_Etc-
((?[^ -]+([. _-]\[.*\])?))?)?$ # Group
'''),
('anime_SxxExx',
# Show.Name.S01E02.Source.Quality.Etc-Group
# Show Name - S01E02 - My Ep Name
# Show.Name.S01.E03.My.Ep.Name
# Show.Name.S01E02E03.Source.Quality.Etc-Group
# Show Name - S01E02-03 - My Ep Name
# Show.Name.S01.E02.E03
# Show Name - S01E02
# Show Name - S01E02-03
r'''
^((?P.+?)[. _-]+)? # Show_Name and separator
(\()?s(?P\d+)[. _-]* # S01 and optional separator
e(?P\d+)(\))? # E02 and separator
(([. _-]*e|-) # linking e/- char
(?P(?!(1080|720|480)[pi])\d+)(\))?)* # additional E03/etc
([. _-]+((?P.+?))? # Source_Quality_Etc-
((?[^ -]+([. _-]\[.*\])?))?)?$ # Group
'''),
('anime_and_normal',
# Bleach - s16e03-04 - 313-314
# Bleach.s16e03-04.313-314
# Bleach s16e03e04 313-314
r'''
^(?P.+?)[ ._-]+ # start of string and series name and non optinal separator
s(?P\d+)[. _-]* # S01 and optional separator
e(?P\d+) # epipisode E02
(([. _-]*e|-) # linking e/- char
(?P\d+))* # additional E03/etc
([ ._-]{2,}|[ ._]+) # if "-" is used to separate at least something else has to be there(->{2,}) "s16e03-04-313-314" would make sens any way
((?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # absolute number
(-(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # "-" as separator and anditional absolute number, all optinal
(v(?P[0-9]))? # the version e.g. "v2"
.*?
'''),
('anime_and_normal_x',
# Bleach - s16e03-04 - 313-314
# Bleach.s16e03-04.313-314
# Bleach s16e03e04 313-314
r'''
^(?P.+?)[ ._-]+ # start of string and series name and non optinal separator
(?P\d+)[. _-]* # S01 and optional separator
[xX](?P\d+) # epipisode E02
(([. _-]*e|-) # linking e/- char
(?P\d+))* # additional E03/etc
([ ._-]{2,}|[ ._]+) # if "-" is used to separate at least something else has to be there(->{2,}) "s16e03-04-313-314" would make sens any way
((?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # absolute number
(-(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # "-" as separator and anditional absolute number, all optinal
(v(?P[0-9]))? # the version e.g. "v2"
.*?
'''),
('anime_and_normal_reverse',
# Bleach - 313-314 - s16e03-04
r'''
^(?P.+?)[ ._-]+ # start of string and series name and non optinal separator
(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}) # absolute number
(-(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # "-" as separator and anditional absolute number, all optinal
(v(?P[0-9]))? # the version e.g. "v2"
([ ._-]{2,}|[ ._]+) # if "-" is used to separate at least something else has to be there(->{2,}) "s16e03-04-313-314" would make sens any way
s(?P\d+)[. _-]* # S01 and optional separator
e(?P\d+) # epipisode E02
(([. _-]*e|-) # linking e/- char
(?P\d+))* # additional E03/etc
.*?
'''),
('anime_and_normal_front',
# 165.Naruto Shippuuden.s08e014
r'''
^(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}) # start of string and absolute number
(-(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # "-" as separator and anditional absolute number, all optinal
(v(?P[0-9]))?[ ._-]+ # the version e.g. "v2"
(?P.+?)[ ._-]+
s(?P\d+)[. _-]* # S01 and optional separator
e(?P\d+)
(([. _-]*e|-) # linking e/- char
(?P\d+))* # additional E03/etc
.*?
'''),
('anime_ep_name',
r'''
^(?:\[(?P.+?)\][ ._-]*)
(?P.+?)[ ._-]+
(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3})
(-(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))?[ ._-]*?
(?:v(?P[0-9])[ ._-]+?)?
(?:.+?[ ._-]+?)?
\[(?P\w+)\][ ._-]?
(?:\[(?P\w{8})\])?
.*?
'''),
('anime_WarB3asT',
# 003. Show Name - Ep Name.ext
# 003-004. Show Name - Ep Name.ext
r'''
^(?P\d{3,4})(-(?P\d{3,4}))?\.\s+(?P.+?)\s-\s.*
'''),
('anime_bare',
# One Piece - 102
# [ACX]_Wolf's_Spirit_001.mkv
r'''
^(\[(?P.+?)\][ ._-]*)?
(?P.+?)[ ._-]+ # Show_Name and separator
(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}) # E01
(-(?P((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # E02
(v(?P[0-9]))? # v2
.*? # Separator and EOL
'''),
]
================================================
FILE: sickrage/core/nameparser/validator.py
================================================
# Author: echel0n
# URL: https://sickrage.ca
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
#
# This file is part of SiCKRAGE.
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
import datetime
import os
from datetime import date
import sickrage
from sickrage.core.enums import SearchFormat, SeriesProviderID
from sickrage.core.nameparser import NameParser
from sickrage.core.common import Quality, Qualities, EpisodeStatus
from sickrage.core.tv.episode import TVEpisode
name_presets = (
'%SN - %Sx%0E - %EN',
'%S.N.S%0SE%0E.%E.N',
'%Sx%0E - %EN',
'S%0SE%0E - %EN',
'Season %0S/%S.N.S%0SE%0E.%Q.N-%RG'
)
name_anime_presets = name_presets
name_abd_presets = (
'%SN - %A-D - %EN',
'%S.N.%A.D.%E.N.%Q.N',
'%Y/%0M/%S.N.%A.D.%E.N-%RG'
)
name_sports_presets = (
'%SN - %A-D - %EN',
'%S.N.%A.D.%E.N.%Q.N',
'%Y/%0M/%S.N.%A.D.%E.N-%RG'
)
class FakeEpisode(object):
def __init__(self, season, episode, absolute_number, name):
self.name = name
self.season = season
self.episode = episode
self.absolute_number = absolute_number
self.airdate = datetime.date(2010, 3, 9)
self.status = Quality.composite_status(EpisodeStatus.DOWNLOADED, Qualities.SDTV)
self.release_name = 'Show.Name.S02E03.HDTV.XviD-RLSGROUP'
self.release_group = 'RLSGROUP'
self.is_proper = True
self.show = FakeShow()
self.scene_season = season
self.scene_episode = episode
self.scene_absolute_number = absolute_number
self.related_episodes = []
self.session = sickrage.app.main_db.session()
def formatted_filename(self, *args, **kwargs):
return TVEpisode.formatted_filename(self, *args, **kwargs)
def _format_pattern(self, *args, **kwargs):
return TVEpisode._format_pattern(self, *args, **kwargs)
def _replace_map(self):
return TVEpisode._replace_map(self)
def _ep_name(self):
return TVEpisode._ep_name(self)
def _format_string(self, *args, **kwargs):
return TVEpisode._format_string(self, *args, **kwargs)
def formatted_dir(self, *args, **kwargs):
return TVEpisode.formatted_dir(self, *args, **kwargs)
class FakeShow(object):
def __init__(self):
self.name = "Show Name"
self.genre = "Comedy"
self.series_id = 0o00001
self.series_provider_id = SeriesProviderID.THETVDB
self.search_format = SearchFormat.STANDARD
self.startyear = 2011
self.anime = 0
def check_force_season_folders(pattern=None, multi=None, anime_type=None):
"""
Checks if the name can still be parsed if you strip off the folders to determine if we need to force season folders
to be enabled or not.
:param pattern: formatting pattern
:param multi: multi-episode
:param anime_type: anime type
:return: true if season folders need to be forced on or false otherwise.
"""
if pattern is None:
pattern = sickrage.app.config.general.naming_pattern
if anime_type is None:
anime_type = sickrage.app.config.general.naming_anime
return not validate_name(pattern, multi, anime_type, file_only=True)
def check_valid_naming(pattern=None, multi=None, anime_type=None):
"""
Checks if the name is can be parsed back to its original form for both single and multi episodes.
:param pattern: formatting pattern
:param multi: multi-episode
:param anime_type: anime type
:return: true if the naming is valid, false if not.
"""
if pattern is None:
pattern = sickrage.app.config.general.naming_pattern
if anime_type is None:
anime_type = sickrage.app.config.general.naming_anime
sickrage.app.log.debug("Checking whether the pattern " + pattern + " is valid")
return validate_name(pattern, multi, anime_type)
def check_valid_abd_naming(pattern=None):
"""
Checks if the name is can be parsed back to its original form for an air-by-date format.
:param pattern: formatting pattern
:return: true if the naming is valid, false if not.
"""
if pattern is None:
pattern = sickrage.app.config.general.naming_pattern
sickrage.app.log.debug("Checking whether the pattern " + pattern + " is valid for an air-by-date episode")
valid = validate_name(pattern, abd=True)
return valid
def check_valid_sports_naming(pattern=None):
"""
Checks if the name is can be parsed back to its original form for an sports format.
:param pattern: formatting pattern
:return: true if the naming is valid, false if not.
"""
if pattern is None:
pattern = sickrage.app.config.general.naming_pattern
sickrage.app.log.debug("Checking whether the pattern " + pattern + " is valid for an sports episode")
valid = validate_name(pattern, sports=True)
return valid
def validate_name(pattern, multi=None, anime_type=None, file_only=False, abd=False, sports=False):
"""
See if we understand a name
:param pattern: Name to analyse
:param multi: Is this a multi-episode name
:param anime_type: Is this anime
:param file_only: Is this just a file or a dir
:param abd: Is air-by-date enabled
:param sports: Is this sports
:return: True if valid name, False if not
"""
ep = generate_sample_ep(multi, abd, sports, anime_type)
new_name = ep.formatted_filename(pattern, multi, anime_type) + '.ext'
new_path = ep.formatted_dir(pattern, multi)
if not file_only:
new_name = os.path.join(new_path, new_name)
if not new_name:
sickrage.app.log.debug("Unable to create a name out of " + pattern)
return False
sickrage.app.log.debug("Trying to parse " + new_name)
parser = NameParser(True, series_id=ep.show.series_id, series_provider_id=ep.show.series_provider_id, naming_pattern=True)
try:
result = parser.parse(new_name)
except Exception:
sickrage.app.log.debug("Unable to parse " + new_name + ", not valid")
return False
sickrage.app.log.debug("Parsed " + new_name + " into " + str(result))
if abd or sports:
if result.air_date != ep.airdate:
sickrage.app.log.debug("Air date incorrect in parsed episode, pattern isn't valid")
return False
elif anime_type != 3:
if len(result.ab_episode_numbers) and result.ab_episode_numbers != [x.absolute_number for x in
[ep] + ep.related_episodes]:
sickrage.app.log.debug("Absolute numbering incorrect in parsed episode, pattern isn't valid")
return False
else:
if result.season_number != ep.season:
sickrage.app.log.debug("Season number incorrect in parsed episode, pattern isn't valid")
return False
if result.episode_numbers != [x.episode for x in [ep] + ep.related_episodes]:
sickrage.app.log.debug("Episode numbering incorrect in parsed episode, pattern isn't valid")
return False
return True
def generate_sample_ep(multi=None, abd=False, sports=False, anime_type=None):
# make a fake episode object
ep = FakeEpisode(2, 3, 3, "Ep Name")
ep.status = Quality.composite_status(EpisodeStatus.DOWNLOADED, Qualities.HDTV)
ep.airdate = date(2011, 3, 9)
if abd:
ep.release_name = 'Show.Name.2011.03.09.HDTV.XviD-RLSGROUP'
ep.show.search_format = SearchFormat.AIR_BY_DATE
elif sports:
ep.release_name = 'Show.Name.2011.03.09.HDTV.XviD-RLSGROUP'
ep.show.search_format = SearchFormat.SPORTS
else:
if anime_type != 3:
ep.show.search_format = SearchFormat.ANIME
ep.release_name = 'Show.Name.003.HDTV.XviD-RLSGROUP'
else:
ep.release_name = 'Show.Name.S02E03.HDTV.XviD-RLSGROUP'
if multi is not None:
ep.name = "Ep Name (1)"
if anime_type != 3:
ep.show.search_format = SearchFormat.ANIME
ep.release_name = 'Show.Name.003-004.HDTV.XviD-RLSGROUP'
second_ep = FakeEpisode(2, 4, 4, "Ep Name (2)")
second_ep.status = Quality.composite_status(EpisodeStatus.DOWNLOADED, Qualities.HDTV)
second_ep.release_name = ep.release_name
ep.related_episodes.append(second_ep)
else:
ep.release_name = 'Show.Name.S02E03E04E05.HDTV.XviD-RLSGROUP'
second_ep = FakeEpisode(2, 4, 4, "Ep Name (2)")
second_ep.status = Quality.composite_status(EpisodeStatus.DOWNLOADED, Qualities.HDTV)
second_ep.release_name = ep.release_name
third_ep = FakeEpisode(2, 5, 5, "Ep Name (3)")
third_ep.status = Quality.composite_status(EpisodeStatus.DOWNLOADED, Qualities.HDTV)
third_ep.release_name = ep.release_name
ep.related_episodes.append(second_ep)
ep.related_episodes.append(third_ep)
return ep
def test_name(pattern, multi=None, abd=False, sports=False, anime_type=None):
ep = generate_sample_ep(multi, abd, sports, anime_type)
return {'name': ep.formatted_filename(pattern, multi, anime_type), 'dir': ep.formatted_dir(pattern, multi)}
================================================
FILE: sickrage/core/nzbSplitter.py
================================================
# Author: echel0n
# URL: https://sickrage.ca
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
#
# This file is part of SiCKRAGE.
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
import re
from xml.etree import ElementTree
import sickrage
from sickrage.core.nameparser import InvalidNameException, InvalidShowException, NameParser
from sickrage.core.tv.show.helpers import find_show
from sickrage.core.websession import WebSession
from sickrage.search_providers import NZBDataSearchProviderResult
def getSeasonNZBs(name, urlData, season):
"""
Split a season NZB into episodes
:param name: NZB name
:param urlData: URL to get data from
:param season: Season to check
:return: dict of (episode files, xml matches)
"""
try:
nzbElement = ElementTree.fromstring(urlData)
except SyntaxError:
sickrage.app.log.error("Unable to parse the XML of " + name + ", not splitting it")
return {}, ''
filename = name.replace(".nzb", "")
regex = r'([\w\._\ ]+)[\. ]S%02d[\. ]([\w\._\-\ ]+)[\- ]([\w_\-\ ]+?)' % season
sceneNameMatch = re.search(regex, filename, re.I)
if sceneNameMatch:
showName, qualitySection, groupName = sceneNameMatch.groups()
else:
sickrage.app.log.error("Unable to parse " + name + " into a scene name. If it's a valid, log a bug.")
return {}, ''
regex = '(' + re.escape(showName) + r'\.S%02d(?:[E0-9]+)\.[\w\._]+\-\w+' % season + ')'
regex = regex.replace(' ', '.')
epFiles = {}
xmlns = None
for curFile in nzbElement.getchildren():
xmlnsMatch = re.match(r"{(http://[A-Za-z0-9_./]+/nzb)\}file", curFile.tag)
if not xmlnsMatch:
continue
else:
xmlns = xmlnsMatch.group(1)
match = re.search(regex, curFile.get("subject"), re.I)
if not match:
# print curFile.get("subject"), "doesn't match", regex
continue
curEp = match.group(1)
if curEp not in epFiles:
epFiles[curEp] = [curFile]
else:
epFiles[curEp].append(curFile)
return epFiles, xmlns
def createNZBString(fileElements, xmlns):
rootElement = ElementTree.Element("nzb")
if xmlns:
rootElement.set("xmlns", xmlns)
for curFile in fileElements:
rootElement.append(stripNS(curFile, xmlns))
return ElementTree.tostring(rootElement)
def saveNZB(nzbName, nzbString):
"""
Save NZB to disk
:param nzbName: Filename/path to write to
:param nzbString: Content to write in file
"""
try:
with open(nzbName + ".nzb", 'w') as nzb_fh:
nzb_fh.write(nzbString)
except EnvironmentError as e:
sickrage.app.log.warning("Unable to save NZB: {}".format(e))
def stripNS(element, ns):
element.tag = element.tag.replace("{" + ns + "}", "")
for curChild in element.getchildren():
stripNS(curChild, ns)
return element
def split_nzb_result(result):
"""
Split result into separate episodes
:param result: search result object
:return: False upon failure, a list of episode objects otherwise
"""
try:
url_data = WebSession().get(result.url, needBytes=True).text
except Exception:
sickrage.app.log.error("Unable to load url " + result.url + ", can't download season NZB")
return False
# parse the season ep name
try:
parse_result = NameParser(False, series_id=result.series_id, series_provider_id=result.series_provider_id).parse(result.name)
except InvalidNameException:
sickrage.app.log.debug("Unable to parse the filename " + result.name + " into a valid episode")
return False
except InvalidShowException:
sickrage.app.log.debug("Unable to parse the filename " + result.name + " into a valid show")
return False
# bust it up
season = parse_result.season_number if parse_result.season_number is not None else 1
separate_nzbs, xmlns = getSeasonNZBs(result.name, url_data, season)
result_list = []
for newNZB in separate_nzbs:
sickrage.app.log.debug("Split out {} from {}".format(newNZB, result.name))
# parse the name
try:
parse_result = NameParser(False, series_id=result.series_id, series_provider_id=result.series_provider_id).parse(newNZB)
except InvalidNameException:
sickrage.app.log.debug("Unable to parse the filename {} into a valid episode".format(newNZB))
return False
except InvalidShowException:
sickrage.app.log.debug("Unable to parse the filename {} into a valid show".format(newNZB))
return False
# make sure the result is sane
if (parse_result.season_number is not None and parse_result.season_number != season) or (parse_result.season_number is None and season != 1):
sickrage.app.log.warning("Found {} inside {} but it doesn't seem to belong to the same season, ignoring it".format(newNZB, result.name))
continue
elif len(parse_result.episode_numbers) == 0:
sickrage.app.log.warning("Found {} inside {} but it doesn't seem to be a valid episode NZB, ignoring it".format(newNZB, result.name))
continue
want_ep = True
for epNo in parse_result.episode_numbers:
show_object = find_show(parse_result.series_id, parse_result.series_provider_id)
if not show_object.want_episode(parse_result.season_number, epNo, result.quality):
sickrage.app.log.info("Ignoring result {} because we don't want an episode that is {}".format(newNZB, result.quality.display_name))
want_ep = False
break
if not want_ep:
continue
# make a result
cur_result = NZBDataSearchProviderResult(season, parse_result.episode_numbers)
cur_result.name = newNZB
cur_result.provider = result.provider
cur_result.quality = result.quality
cur_result.extraInfo = [createNZBString(separate_nzbs[newNZB], xmlns)]
result_list.append(cur_result)
return result_list
================================================
FILE: sickrage/core/process_tv.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import os
import shutil
import stat
import rarfile
from sqlalchemy import or_
import sickrage
from sickrage.core.common import EpisodeStatus
from sickrage.core.databases.main import MainDB
from sickrage.core.enums import ProcessMethod
from sickrage.core.exceptions import EpisodePostProcessingFailedException, FailedPostProcessingFailedException, NoFreeSpaceException
from sickrage.core.helpers import is_media_file, is_rar_file, is_hidden_folder, real_path, is_torrent_or_nzb_file, is_sync_file, get_extension
from sickrage.core.nameparser import InvalidNameException, InvalidShowException, NameParser
from sickrage.core.processors import failed_processor, post_processor
from sickrage.core.tv.show.helpers import get_show_list
class ProcessResult(object):
def __init__(self, path, process_method=None, process_type='auto'):
self._output = []
self._path = path
self.process_method = process_method or sickrage.app.config.general.process_method
self.process_type = process_type
self.video_files = []
self.missed_files = []
self.result = True
self.succeeded = True
@property
def path(self):
return self._path
@path.setter
def path(self, value):
dir_name = None
if os.path.isdir(value):
dir_name = os.path.realpath(value)
self.log("Processing in folder {0}".format(dir_name), sickrage.app.log.DEBUG)
elif all([sickrage.app.config.general.tv_download_dir,
os.path.isdir(sickrage.app.config.general.tv_download_dir),
os.path.normpath(value) == os.path.normpath(sickrage.app.config.general.tv_download_dir)]):
dir_name = os.path.join(sickrage.app.config.general.tv_download_dir,
os.path.abspath(value).split(os.path.sep)[-1])
self.log("Trying to use folder: {0} ".format(dir_name), sickrage.app.log.DEBUG)
else:
self.log("Unable to figure out what folder to process. "
"If your downloader and SiCKRAGE aren't on the same PC "
"make sure you fill out your TV download dir in the config.",
sickrage.app.log.DEBUG)
self._path = dir_name
@property
def output(self):
return '\n'.join(self._output)
def log(self, message, level=None):
sickrage.app.log.log(level or sickrage.app.log.INFO, message)
self._output.append(message)
def clear_log(self):
self._output = []
def delete_folder(self, folder, check_empty=True):
"""
Removes a folder from the filesystem
:param folder: Path to folder to remove
:param check_empty: Boolean, check if the folder is empty before removing it, defaults to True
:return: True on success, False on failure
"""
# check if it's a folder
if not os.path.isdir(folder):
return False
# check if it isn't TV_DOWNLOAD_DIR
if sickrage.app.config.general.tv_download_dir:
if real_path(folder) == real_path(sickrage.app.config.general.tv_download_dir):
return False
# check if it's empty folder when wanted checked
try:
if check_empty:
check_files = os.listdir(folder)
if check_files:
sickrage.app.log.info(
"Not deleting folder {} found the following files: {}".format(folder, check_files))
return False
sickrage.app.log.info("Deleting folder (if it's empty): " + folder)
shutil.rmtree(folder)
else:
sickrage.app.log.info("Deleting folder: " + folder)
shutil.rmtree(folder)
except (OSError, IOError) as e:
sickrage.app.log.warning("Warning: unable to delete folder: {}: {}".format(folder, e))
return False
return True
def delete_files(self, processPath, notwantedFiles, force=False):
"""
Remove files from filesystem
:param processPath: path to process
:param notwantedFiles: files we do not want
:param force: Boolean, force deletion, defaults to false
"""
if not self.result and force:
self.log("Forcing deletion of files, even though last result was not success",
sickrage.app.log.DEBUG)
elif not self.result:
return
# Delete all file not needed
for cur_file in notwantedFiles:
cur_file_path = os.path.join(processPath, cur_file)
if not os.path.isfile(cur_file_path):
continue # Prevent error when a notwantedfiles is an associated files
self.log("Deleting file %s" % cur_file, sickrage.app.log.DEBUG)
# check first the read-only attribute
file_attribute = os.stat(cur_file_path)[0]
if not file_attribute & stat.S_IWRITE:
# File is read-only, so make it writeable
self.log("Changing ReadOnly Flag for file {}".format(cur_file),
sickrage.app.log.DEBUG)
try:
os.chmod(cur_file_path, stat.S_IWRITE)
except OSError as e:
self.log("Cannot change permissions of {}: {}".format(cur_file, e.strerror),
sickrage.app.log.DEBUG)
try:
os.remove(cur_file_path)
except OSError as e:
self.log("Unable to delete file {}: {}".format(cur_file, e.strerror),
sickrage.app.log.DEBUG)
def process(self, nzbName=None, force=False, is_priority=None, delete_on=False, failed=False):
"""
Scans through the files in dir_name and processes whatever media files it finds
:param nzbName: The NZB name which resulted in this folder being downloaded
:param force: True to postprocess already postprocessed files
:param is_priority: whether to replace the file even if it exists at higher quality
:param delete_on: delete files and folders after they are processed (always happens with move and auto combination)
:param failed: Boolean for whether or not the download failed
"""
self.clear_log()
directories_from_rars = set()
# If we have a release name (probably from nzbToMedia), and it is a rar/video, only process that file
if nzbName and (is_media_file(nzbName) or is_rar_file(nzbName)):
self.log("Processing {}".format(nzbName), sickrage.app.log.INFO)
generator_to_use = [(self.path, [], [nzbName])]
else:
self.log("Processing {}".format(self.path), sickrage.app.log.INFO)
generator_to_use = os.walk(self.path, followlinks=sickrage.app.config.general.processor_follow_symlinks)
rar_files = []
for current_directory, directory_names, file_names in generator_to_use:
self.result = True
file_names = [f for f in file_names if not is_torrent_or_nzb_file(f)]
rar_files = [x for x in file_names if is_rar_file(os.path.join(current_directory, x))]
if rar_files:
extracted_directories = self.unrar(current_directory, rar_files, force)
if extracted_directories:
for extracted_directory in extracted_directories:
if extracted_directory.split(current_directory)[-1] not in directory_names:
self.log(
"Adding extracted directory to the list of directories to process: {0}".format(
extracted_directory), sickrage.app.log.DEBUG
)
directories_from_rars.add(extracted_directory)
if not self.validateDir(current_directory, nzbName, failed):
continue
video_files = list(filter(is_media_file, file_names))
if video_files:
try:
self.process_media(current_directory, video_files, nzbName, self.process_method, force, is_priority)
except NoFreeSpaceException:
continue
else:
self.result = False
# Delete all file not needed and avoid deleting files if Manual PostProcessing
if not (self.process_method == ProcessMethod.MOVE and self.result) or (self.process_type == "manual" and not delete_on):
continue
# Check for unwanted files
unwanted_files = list(
filter(
lambda x: x not in video_files and get_extension(x) not in sickrage.app.config.general.allowed_extensions,
file_names)
)
if unwanted_files:
self.log("Found unwanted files: {0}".format(unwanted_files), sickrage.app.log.DEBUG)
self.delete_folder(os.path.join(current_directory, '@eaDir'), False)
self.delete_files(current_directory, unwanted_files)
if self.delete_folder(current_directory, check_empty=not delete_on):
self.log("Deleted folder: {0}".format(current_directory), sickrage.app.log.DEBUG)
method_fallback = (ProcessMethod.MOVE, self.process_method)[self.process_method in (ProcessMethod.MOVE, ProcessMethod.COPY)]
delete_rar_contents = any([sickrage.app.config.general.del_rar_contents and self.process_type != 'manual',
not sickrage.app.config.general.del_rar_contents and self.process_type == 'auto' and method_fallback == ProcessMethod.MOVE,
self.process_type == 'manual' and delete_on])
for directory_from_rar in directories_from_rars:
ProcessResult(directories_from_rars, self.process_method, self.process_type).process(
nzbName=os.path.basename(directory_from_rar),
force=force,
is_priority=is_priority,
delete_on=delete_rar_contents,
failed=failed
)
# Delete rar file only if the extracted dir was successfully processed
if self.process_type == 'auto' and method_fallback == ProcessMethod.MOVE or self.process_type == 'manual' and delete_on:
this_rar = [rar_file for rar_file in rar_files if
os.path.basename(directory_from_rar) == rar_file.rpartition('.')[0]]
self.delete_files(self.path, this_rar)
self.log(("Processing Failed", "Successfully processed")[self.succeeded],
(sickrage.app.log.WARNING, sickrage.app.log.INFO)[self.succeeded])
if self.missed_files:
self.log("Some items were not processed.")
for missed_file in self.missed_files:
self.log(missed_file)
return self.output
def validateDir(self, process_path, release_name, failed):
"""
Check if directory is valid for processing
:param process_path: Directory to check
:param release_name: Original NZB/Torrent name
:param failed: Previously failed objects
:return: True if dir is valid for processing, False if not
"""
self.log("Processing folder " + process_path, sickrage.app.log.DEBUG)
upper_name = os.path.basename(process_path).upper()
if upper_name.startswith('_FAILED_') or upper_name.endswith('_FAILED_'):
self.log("The directory name indicates it failed to extract.", sickrage.app.log.DEBUG)
failed = True
elif upper_name.startswith('_UNDERSIZED_') or upper_name.endswith('_UNDERSIZED_'):
self.log(
"The directory name indicates that it was previously rejected for being undersized.",
sickrage.app.log.DEBUG)
failed = True
elif upper_name.startswith('_UNPACK') or upper_name.endswith('_UNPACK'):
self.log(
"The directory name indicates that this release is in the process of being unpacked.",
sickrage.app.log.DEBUG)
self.missed_files.append("{0} : Being unpacked".format(process_path))
return False
if failed:
self.process_failed(process_path, release_name)
self.missed_files.append("{0} : Failed download".format(process_path))
return False
if sickrage.app.config.general.tv_download_dir and real_path(process_path) != real_path(
sickrage.app.config.general.tv_download_dir) and is_hidden_folder(process_path):
self.log("Ignoring hidden folder: {0}".format(process_path), sickrage.app.log.DEBUG)
self.missed_files.append("{0} : Hidden folder".format(process_path))
return False
# make sure the dir isn't inside a show dir
for show in get_show_list():
if process_path.lower().startswith(os.path.realpath(show.location).lower() + os.sep) or \
process_path.lower() == os.path.realpath(show.location).lower():
self.log("Cannot process an episode that's already been moved to its show dir, skipping " + process_path, sickrage.app.log.WARNING)
return False
for current_directory, directory_names, file_names in os.walk(process_path, topdown=False,
followlinks=sickrage.app.config.general.processor_follow_symlinks):
sync_files = list(filter(is_sync_file, file_names))
if sync_files and sickrage.app.config.general.postpone_if_sync_files:
self.log("Found temporary sync files: {0} in path: {1}".format(sync_files,
os.path.join(
process_path,
sync_files[
0])))
self.log("Skipping post processing for folder: {0}".format(process_path))
self.missed_files.append("{0} : Sync files found".format(os.path.join(process_path, sync_files[0])))
continue
found_files = list(filter(is_media_file, file_names))
if sickrage.app.config.general.unpack == 1:
found_files += list(filter(is_rar_file, file_names))
if current_directory != sickrage.app.config.general.tv_download_dir and found_files:
found_files.append(os.path.basename(current_directory))
for found_file in found_files:
try:
NameParser().parse(found_file, cache_result=False)
except (InvalidNameException, InvalidShowException) as e:
pass
else:
return True
self.log("Folder {} : No processable items found in folder".format(process_path),
sickrage.app.log.DEBUG)
return False
def unrar(self, path, rar_files, force):
"""
Extracts RAR files
:param path: Path to look for files in
:param rar_files: Names of RAR files
:param force: process currently processing items
:return: List of unpacked file names
"""
unpacked_dirs = []
if sickrage.app.config.general.unpack == 1 and rar_files:
self.log("Packed Releases detected: {0}".format(rar_files), sickrage.app.log.DEBUG)
for archive in rar_files:
failure = None
rar_handle = None
try:
archive_path = os.path.join(path, archive)
if self.already_postprocessed(path, archive, force):
self.log("Archive file already post-processed, extraction skipped: {}".format
(archive_path), sickrage.app.log.DEBUG)
continue
if not is_rar_file(archive_path):
continue
self.log(
"Checking if archive is valid and contains a video: {}".format(archive_path),
sickrage.app.log.DEBUG)
rar_handle = rarfile.RarFile(archive_path)
if rar_handle.needs_password():
# TODO: Add support in settings for a list of passwords to try here with rar_handle.set_password(x)
self.log('Archive needs a password, skipping: {0}'.format(archive_path))
continue
# If there are no video files in the rar, don't extract it
rar_media_files = list(filter(is_media_file, rar_handle.namelist()))
if not rar_media_files:
continue
rar_release_name = archive.rpartition('.')[0]
# Choose the directory we'll unpack to:
if sickrage.app.config.general.unpack_dir and os.path.isdir(sickrage.app.config.general.unpack_dir):
unpack_base_dir = sickrage.app.config.general.unpack_dir
else:
unpack_base_dir = path
if sickrage.app.config.general.unpack_dir: # Let user know if we can't unpack there
self.log('Unpack directory cannot be verified. Using {}'.format(path),
sickrage.app.log.DEBUG)
# Fix up the list for checking if already processed
rar_media_files = [os.path.join(unpack_base_dir, rar_release_name, rar_media_file) for
rar_media_file in
rar_media_files]
skip_rar = False
for rar_media_file in rar_media_files:
check_path, check_file = os.path.split(rar_media_file)
if self.already_postprocessed(check_path, check_file, force):
self.log(
"Archive file already post-processed, extraction skipped: {0}".format
(rar_media_file), sickrage.app.log.DEBUG)
skip_rar = True
break
if skip_rar:
continue
rar_extract_path = os.path.join(unpack_base_dir, rar_release_name)
self.log("Unpacking archive: {0}".format(archive), sickrage.app.log.DEBUG)
rar_handle.extractall(path=rar_extract_path)
unpacked_dirs.append(rar_extract_path)
except rarfile.RarCRCError:
failure = ('Archive Broken', 'Unpacking failed because of a CRC error')
except rarfile.RarWrongPassword:
failure = ('Incorrect RAR Password', 'Unpacking failed because of an Incorrect Rar Password')
except rarfile.PasswordRequired:
failure = ('Rar is password protected', 'Unpacking failed because it needs a password')
except rarfile.RarOpenError:
failure = ('Rar Open Error, check the parent folder and destination file permissions.',
'Unpacking failed with a File Open Error (file permissions?)')
except rarfile.RarExecError:
failure = ('Invalid Rar Archive Usage',
'Unpacking Failed with Invalid Rar Archive Usage. Is unrar installed and on the system '
'PATH?')
except rarfile.BadRarFile:
failure = ('Invalid Rar Archive', 'Unpacking Failed with an Invalid Rar Archive Error')
except rarfile.NeedFirstVolume:
continue
except (Exception, rarfile.Error) as e:
failure = (e, 'Unpacking failed')
finally:
if rar_handle:
del rar_handle
if failure:
self.log('Failed to extract the archive {}: {}'.format(archive, failure[0]),
sickrage.app.log.WARNING)
self.missed_files.append('{} : Unpacking failed: {}'.format(archive, failure[1]))
self.result = False
continue
return unpacked_dirs
def already_postprocessed(self, dirName, videofile, force):
"""
Check if we already post processed a file
:param dirName: Directory a file resides in
:param videofile: File name
:param force: Force checking when already checking (currently unused)
:return:
"""
if force:
return False
session = sickrage.app.main_db.session()
# Avoid processing the same dir again if we use a process method <> move
if session.query(MainDB.TVEpisode).filter(
or_(MainDB.TVEpisode.release_name.contains(dirName), MainDB.TVEpisode.release_name.contains(videofile))).count() > 0:
return True
# Needed if we have downloaded the same episode @ different quality
# But we need to make sure we check the history of the episode we're going to PP, and not others
np = NameParser(dirName)
try:
parse_result = np.parse(dirName)
except:
parse_result = False
for h in session.query(MainDB.History).filter(MainDB.History.resource.endswith(videofile)):
for e in session.query(MainDB.TVEpisode).filter_by(series_id=h.series_id, season=h.season, episode=h.episode).filter(
MainDB.TVEpisode.status.in_(EpisodeStatus.composites(EpisodeStatus.DOWNLOADED))):
if parse_result and (parse_result.series_id and parse_result.episode_numbers and parse_result.season_number):
if e.series_id == int(parse_result.series_id) and e.season == int(parse_result.season_number and e.episode) == int(
parse_result.episode_numbers[0]):
return True
else:
return True
# Checks for processed file marker
if os.path.isfile(os.path.join(dirName, videofile + '.sr_processed')):
return True
return False
def process_media(self, processPath, videoFiles, nzbName, process_method, force, is_priority):
"""
Postprocess mediafiles
:param processPath: Path to postprocess in
:param videoFiles: Filenames to look for and postprocess
:param nzbName: Name of NZB file related
:param process_method: auto/manual
:param force: Postprocess currently postprocessing file
:param is_priority: Boolean, is this a priority download
"""
processor = None
for cur_video_file in videoFiles:
cur_video_file_path = os.path.join(processPath, cur_video_file)
if self.already_postprocessed(processPath, cur_video_file, force):
self.log("Skipping already processed file: {0}".format(cur_video_file), sickrage.app.log.DEBUG)
continue
try:
processor = post_processor.PostProcessor(cur_video_file_path, nzbName, process_method, is_priority)
self.result = processor.process()
process_fail_message = ""
except EpisodePostProcessingFailedException as e:
self.result = False
process_fail_message = "{}".format(e)
if processor:
self._output.append(processor.log)
if self.result:
self.log("Processing succeeded for " + cur_video_file_path)
else:
self.log("Processing failed for {0}: {1}".format(cur_video_file_path, process_fail_message), sickrage.app.log.WARNING)
self.missed_files.append("{0} : Processing failed: {1}".format(cur_video_file_path, process_fail_message))
self.succeeded = False
def process_failed(self, dirName, nzbName):
"""Process a download that did not complete correctly"""
try:
processor = failed_processor.FailedProcessor(dirName, nzbName)
self.result = processor.process()
process_fail_message = ""
except FailedPostProcessingFailedException as e:
processor = None
self.result = False
process_fail_message = e
if processor:
self._output.append(processor.log)
if sickrage.app.config.failed_downloads.enable and self.result:
if self.delete_folder(dirName, check_empty=False):
self.log("Deleted folder: " + dirName, sickrage.app.log.DEBUG)
if self.result:
self.log(
"Failed Download Processing succeeded: (" + str(nzbName) + ", " + dirName + ")")
else:
self.log("Failed Download Processing failed: ({}, {}): {}"
.format(nzbName, dirName, process_fail_message),
sickrage.app.log.WARNING)
================================================
FILE: sickrage/core/processors/__init__.py
================================================
================================================
FILE: sickrage/core/processors/auto_postprocessor.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import threading
import sickrage
class AutoPostProcessor(object):
def __init__(self):
self.name = "POSTPROCESSOR"
self.lock = threading.Lock()
self.running = False
def task(self, force=False):
"""
Runs the postprocessor
:param force: Forces postprocessing run (reserved for future use)
:return: Returns when done without a return state/code
"""
if self.running or not sickrage.app.config.general.process_automatically and not force:
return
try:
self.running = True
# set thread name
threading.current_thread().name = self.name
sickrage.app.postprocessor_queue.put(sickrage.app.config.general.tv_download_dir, force=force)
finally:
self.running = False
================================================
FILE: sickrage/core/processors/failed_processor.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import sickrage
from sickrage.core.exceptions import FailedPostProcessingFailedException, EpisodeNotFoundException
from sickrage.core.helpers import show_names
from sickrage.core.nameparser import InvalidNameException, InvalidShowException, NameParser
from sickrage.core.common import Quality, EpisodeStatus
from sickrage.core.queues.search import FailedSearchTask
from sickrage.core.tv.show.helpers import find_show
class FailedProcessor(object):
"""Take appropriate action when a download fails to complete"""
def __init__(self, dirName, nzbName):
"""
:param dirName: Full path to the folder of the failed download
:param nzbName: Full name of the nzb file that failed
"""
self.dir_name = dirName
self.nzb_name = nzbName
self.log = ""
def process(self):
"""
Do the actual work
:return: True
"""
self._log("Failed download detected: (" + str(self.nzb_name) + ", " + str(self.dir_name) + ")")
release_name = show_names.determine_release_name(self.dir_name, self.nzb_name)
if release_name is None:
self._log("Warning: unable to find a valid release name.", sickrage.app.log.WARNING)
raise FailedPostProcessingFailedException()
try:
parsed = NameParser(False).parse(release_name)
except InvalidNameException:
self._log("Error: release name is invalid: " + release_name, sickrage.app.log.DEBUG)
raise FailedPostProcessingFailedException()
except InvalidShowException:
self._log("Error: unable to parse release name " + release_name + " into a valid show",
sickrage.app.log.DEBUG)
raise FailedPostProcessingFailedException()
series = find_show(parsed.series_id, parsed.series_provider_id)
if not series:
raise FailedPostProcessingFailedException()
if series.paused:
self._log("Warning: skipping failed processing for {} because the show is paused".format(release_name), sickrage.app.log.DEBUG)
raise FailedPostProcessingFailedException()
sickrage.app.log.debug("name_parser info: ")
sickrage.app.log.debug(" - " + str(parsed.series_name))
sickrage.app.log.debug(" - " + str(parsed.season_number))
sickrage.app.log.debug(" - " + str(parsed.episode_numbers))
sickrage.app.log.debug(" - " + str(parsed.extra_info))
sickrage.app.log.debug(" - " + str(parsed.release_group))
sickrage.app.log.debug(" - " + str(parsed.air_date))
for episode in parsed.episode_numbers:
try:
episode_obj = series.get_episode(parsed.season_number, episode)
except EpisodeNotFoundException as e:
continue
cur_status, cur_quality = Quality.split_composite_status(episode_obj.status)
if cur_status not in (EpisodeStatus.SNATCHED, EpisodeStatus.SNATCHED_BEST, EpisodeStatus.SNATCHED_PROPER):
continue
sickrage.app.search_queue.put(FailedSearchTask(parsed.series_id, parsed.series_provider_id, episode_obj.season, episode_obj.episode))
return True
def _log(self, message, level=None):
"""Log to regular logfile and save for return for PP script log"""
sickrage.app.log.log(level or sickrage.app.log.INFO, message)
self.log += message + "\n"
================================================
FILE: sickrage/core/processors/post_processor.py
================================================
# ##############################################################################
# Author: echel0n
# URL: https://sickrage.ca/
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
# -
# This file is part of SiCKRAGE.
# -
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# -
# SiCKRAGE 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 General Public License for more details.
# -
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see .
# ##############################################################################
import datetime
import fnmatch
import glob
import os
import re
import stat
import subprocess
from sqlalchemy import orm
import sickrage
from sickrage.core.common import Quality, Qualities, EpisodeStatus
from sickrage.core.databases.main import MainDB
from sickrage.core.enums import ProcessMethod
from sickrage.core.exceptions import EpisodePostProcessingFailedException, NoFreeSpaceException
from sickrage.core.helpers import show_names, replace_extension, make_dir, chmod_as_parent, move_file, copy_file, hardlink_file, move_and_symlink_file, \
remove_non_release_groups, remove_extension, is_file_locked, verify_freespace, delete_empty_folders, make_dirs, symlink, is_rar_file, glob_escape, \
touch_file, flatten
from sickrage.core.helpers.anidb import get_anime_episode
from sickrage.core.nameparser import InvalidNameException, InvalidShowException, NameParser
from sickrage.core.tv.show.helpers import find_show
from sickrage.core.tv.show.history import FailedHistory, History
from sickrage.notification_providers import NotificationProvider
from sickrage.subtitles import Subtitles
class PostProcessor(object):
"""
A class which will process a media file according to the post processing settings in the config.
"""
EXISTS_LARGER = 1
EXISTS_SAME = 2
EXISTS_SMALLER = 3
DOESNT_EXIST = 4
IGNORED_FILESTRINGS = [".AppleDouble", ".DS_Store", ".sr_processed"]
def __init__(self, file_path, nzb_name=None, process_method=None, is_priority=None):
"""
Creates a new post processor with the given file path and optionally an NZB name.
file_path: The path to the file to be processed
nzb_name: The name of the NZB which resulted in this file being downloaded (optional)
"""
# absolute path to the folder that is being processed
self.folder_path = os.path.dirname(os.path.abspath(file_path))
# full path to file
self.file_path = file_path
# file name only
self.file_name = os.path.basename(file_path)
# the name of the folder only
self.folder_name = os.path.basename(self.folder_path)
# name of the NZB that resulted in this folder
self.nzb_name = nzb_name
self.process_method = process_method if process_method else sickrage.app.config.general.process_method
self.in_history = False
self.release_name = None
self.is_proper = False
self.is_priority = is_priority
self.log = ''
self.version = None
self.anidbEpisode = None
def _log(self, message, level=None):
"""
A wrapper for the internal logger which also keeps track of messages and saves them to a string for later.
:param message: The string to log (unicode)
:param level: The log level to use (optional)
"""
sickrage.app.log.log(level or sickrage.app.log.INFO, message)
self.log += message + '\n'
def _checkForExistingFile(self, existing_file):
"""
Checks if a file exists already and if it does whether it's bigger or smaller than
the file we are post processing
;param existing_file: The file to compare to
:return:
DOESNT_EXIST if the file doesn't exist
EXISTS_LARGER if the file exists and is larger than the file we are post processing
EXISTS_SMALLER if the file exists and is smaller than the file we are post processing
EXISTS_SAME if the file exists and is the same size as the file we are post processing
"""
if not existing_file:
self._log("There is no existing file so there's no worries about replacing it", sickrage.app.log.DEBUG)
return PostProcessor.DOESNT_EXIST
# if the new file exists, return the appropriate code depending on the size
if os.path.isfile(existing_file):
# see if it's bigger than our old file
if os.path.getsize(existing_file) > os.path.getsize(self.file_path):
self._log("File " + existing_file + " is larger than " + self.file_path, sickrage.app.log.DEBUG)
return PostProcessor.EXISTS_LARGER
elif os.path.getsize(existing_file) == os.path.getsize(self.file_path):
self._log("File " + existing_file + " is the same size as " + self.file_path, sickrage.app.log.DEBUG)
return PostProcessor.EXISTS_SAME
else:
self._log("File " + existing_file + " is smaller than " + self.file_path, sickrage.app.log.DEBUG)
return PostProcessor.EXISTS_SMALLER
else:
self._log("File " + existing_file + " doesn't exist so there's no worries about replacing it",
sickrage.app.log.DEBUG)
return PostProcessor.DOESNT_EXIST
def list_associated_files(self, file_path, subtitles_only=False, subfolders=False, rename=False):
"""
For a given file path searches for files with the same name but different extension and returns their absolute paths
:param rename:
:param subfolders:
:param subtitles_only:
:param file_path: The file to check for associated files
:return: A list containing all files which are associated to the given file
"""
def recursive_glob(treeroot, pattern):
results = []
for base, __, files in os.walk(treeroot, followlinks=sickrage.app.config.general.processor_follow_symlinks):
goodfiles = fnmatch.filter(files, pattern)
for f in goodfiles:
found = os.path.join(base, f)
if found != file_path:
results.append(found)
return results
if not file_path:
return []
file_path_list_to_allow = []
file_path_list_to_delete = []
if subfolders:
base_name = os.path.basename(file_path).rpartition('.')[0]
else:
base_name = file_path.rpartition('.')[0]
# don't strip it all and use cwd by accident
if not base_name:
return []
dirname = os.path.dirname(file_path) or '.'
# subfolders are only checked in show folder, so names will always be exactly alike
if subfolders:
# just create the list of all files starting with the basename
filelist = recursive_glob(dirname, glob_escape(base_name) + '*')
# this is called when PP, so we need to do the filename check case-insensitive
else:
filelist = []
# loop through all the files in the folder, and check if they are the same name even when the cases don't
# match
for found_file in glob.glob(os.path.join(glob_escape(dirname), '*')):
file_name, separator, file_extension = found_file.rpartition('.')
# Handles subtitles with language code
if file_extension in Subtitles().subtitle_extensions and file_name.rpartition('.')[0].lower() == base_name.lower():
filelist.append(found_file)
# Handles all files with same basename, including subtitles without language code
elif file_name.lower() == base_name.lower():
filelist.append(found_file)
for associated_file_path in filelist:
# Exclude the video file we are post-processing
if os.path.abspath(associated_file_path) == os.path.abspath(file_path):
continue
# If this is a rename in the show folder, we don't need to check anything, just add it to the list
if rename:
file_path_list_to_allow.append(associated_file_path)
continue
# Exclude non-subtitle files with the 'subtitles_only' option
if subtitles_only and not associated_file_path.endswith(tuple(Subtitles().subtitle_extensions)):
continue
# Exclude .rar files from associated list
if is_rar_file(associated_file_path):
continue
# Define associated files (all, allowed and non allowed)
if os.path.isfile(associated_file_path):
# check if allowed or not during post processing
if sickrage.app.config.general.move_associated_files and associated_file_path.endswith(
tuple(sickrage.app.config.general.allowed_extensions.split(","))):
file_path_list_to_allow.append(associated_file_path)
elif sickrage.app.config.general.delete_non_associated_files:
file_path_list_to_delete.append(associated_file_path)
if file_path_list_to_allow or file_path_list_to_delete:
self._log("Found the following "
"associated files for {}: {}".format(file_path, file_path_list_to_allow + file_path_list_to_delete), sickrage.app.log.DEBUG)
if file_path_list_to_delete:
self._log("Deleting non allowed associated files for {}: {}".format(file_path, file_path_list_to_delete), sickrage.app.log.DEBUG)
# Delete all extensions the user doesn't allow
self._delete(file_path_list_to_delete)
if file_path_list_to_allow:
self._log("Allowing associated files for {0}: {1}".format(file_path, file_path_list_to_allow), sickrage.app.log.DEBUG)
else:
self._log("No associated files for {0} were found during this pass".format(file_path), sickrage.app.log.DEBUG)
return file_path_list_to_allow
def _delete(self, file_path, associated_files=False):
"""
Deletes the file and optionally all associated files.
:param file_path: The file to delete
:param associated_files: True to delete all files which differ only by extension, False to leave them
"""
if not file_path:
return
# figure out which files we want to delete
file_list = file_path
if not isinstance(file_path, list):
file_list = [file_path]
if associated_files:
file_list = file_list + self.list_associated_files(file_path, subfolders=True)
if not file_list:
self._log("There were no files associated with " + file_path + ", not deleting anything",
sickrage.app.log.DEBUG)
return
# delete the file and any other files which we want to delete
for cur_file in file_list:
if os.path.isfile(cur_file):
self._log("Deleting file " + cur_file, sickrage.app.log.DEBUG)
# check first the read-only attribute
file_attribute = os.stat(cur_file)[0]
if not file_attribute & stat.S_IWRITE:
# File is read-only, so make it writeable
self._log('Read only mode on file ' + cur_file + ' Will try to make it writeable',
sickrage.app.log.DEBUG)
try:
os.chmod(cur_file, stat.S_IWRITE)
except Exception:
self._log('Cannot change permissions of ' + cur_file, sickrage.app.log.WARNING)
os.remove(cur_file)
# do the library update for synoindex
sickrage.app.notification_providers['synoindex'].deleteFile(cur_file)
def _combined_file_operation(self, file_path, new_path, new_base_name, associated_files=False, action=None,
subs=False):
"""
Performs a generic operation (move or copy) on a file. Can rename the file as well as change its location,
and optionally move associated files too.
:param file_path: The full path of the media file to act on
:param new_path: Destination path where we want to move/copy the file to
:param new_base_name: The base filename (no extension) to use during the copy. Use None to keep the same name.
:param associated_files: Boolean, whether we should copy similarly-named files too
:param action: function that takes an old path and new path and does an operation with them (move/copy)
:param subs: Boolean, whether we should process subtitles too
"""
if not action:
self._log("Must provide an action for the combined file operation", sickrage.app.log.WARNING)
return
file_list = [file_path]
subfolders = os.path.normpath(os.path.dirname(file_path)) != os.path.normpath(
sickrage.app.config.general.tv_download_dir)
if associated_files:
file_list = file_list + self.list_associated_files(file_path, subfolders=subfolders)
elif subs:
file_list = file_list + self.list_associated_files(file_path, subtitles_only=True, subfolders=subfolders)
if not file_list:
self._log("There were no files associated with " + file_path + ", not moving anything",
sickrage.app.log.DEBUG)
return
# create base name with file_path (media_file without .extension)
old_base_name = file_path.rpartition('.')[0]
old_base_name_length = len(old_base_name)
# deal with all files
for cur_file_path in file_list:
cur_file_name = os.path.basename(cur_file_path)
# get the extension without .
cur_extension = cur_file_path[old_base_name_length + 1:]
# check if file have subtitles language
if os.path.splitext(cur_extension)[1][1:] in Subtitles().subtitle_extensions:
cur_lang = os.path.splitext(cur_extension)[0]
if cur_lang in Subtitles().wanted_languages():
cur_extension = cur_lang + os.path.splitext(cur_extension)[1]
# replace .nfo with .nfo-orig to avoid conflicts
if cur_extension == 'nfo' and sickrage.app.config.general.nfo_rename is True:
cur_extension = 'nfo-orig'
# If new base name then convert name
if new_base_name:
new_file_name = new_base_name + '.' + cur_extension
# if we're not renaming we still want to change extensions sometimes
else:
new_file_name = replace_extension(cur_file_name, cur_extension)
if sickrage.app.config.subtitles.dir and cur_extension in Subtitles().subtitle_extensions:
subs_new_path = os.path.join(new_path, sickrage.app.config.subtitles.dir)
dir_exists = make_dir(subs_new_path)
if not dir_exists:
sickrage.app.log.warning("Unable to create subtitles folder " + subs_new_path)
else:
chmod_as_parent(subs_new_path)
new_file_path = os.path.join(subs_new_path, new_file_name)
else:
new_file_path = os.path.join(new_path, new_file_name)
action(cur_file_path, new_file_path)
def _move(self, file_path, new_path, new_base_name, associated_files=False, subs=False):
"""
Move file and set proper permissions
:param file_path: The full path of the media file to move
:param new_path: Destination path where we want to move the file to
:param new_base_name: The base filename (no extension) to use during the move. Use None to keep the same name.
:param associated_files: Boolean, whether we should move similarly-named files too
"""
def _int_move(cur_file_path, new_file_path):
self._log("Moving file from " + cur_file_path + " to " + new_file_path, sickrage.app.log.DEBUG)
try:
move_file(cur_file_path, new_file_path)
chmod_as_parent(new_file_path)
except (IOError, OSError) as e:
self._log("Unable to move file {} to {}: {}".format(cur_file_path, new_file_path, e),
sickrage.app.log.WARNING)
raise
self._combined_file_operation(file_path, new_path, new_base_name, associated_files, action=_int_move,
subs=subs)
def _copy(self, file_path, new_path, new_base_name, associated_files=False, subs=False):
"""
Copy file and set proper permissions
:param file_path: The full path of the media file to copy
:param new_path: Destination path where we want to copy the file to
:param new_base_name: The base filename (no extension) to use during the copy. Use None to keep the same name.
:param associated_files: Boolean, whether we should copy similarly-named files too
"""
def _int_copy(cur_file_path, new_file_path):
self._log("Copying file from " + cur_file_path + " to " + new_file_path, sickrage.app.log.DEBUG)
try:
copy_file(cur_file_path, new_file_path)
chmod_as_parent(new_file_path)
except (IOError, OSError) as e:
self._log("Unable to copy file {} to {}: {}".format(cur_file_path, new_file_path, e),
sickrage.app.log.WARNING)
raise
self._combined_file_operation(file_path, new_path, new_base_name, associated_files, action=_int_copy,
subs=subs)
def _hardlink(self, file_path, new_path, new_base_name, associated_files=False, subs=False):
"""
Hardlink file and set proper permissions
:param file_path: The full path of the media file to move
:param new_path: Destination path where we want to create a hard linked file
:param new_base_name: The base filename (no extension) to use during the link. Use None to keep the same name.
:param associated_files: Boolean, whether we should move similarly-named files too
"""
def _int_hard_link(cur_file_path, new_file_path):
self._log("Hard linking file from " + cur_file_path + " to " + new_file_path,
sickrage.app.log.DEBUG)
try:
if os.path.exists(new_file_path):
os.remove(new_file_path)
hardlink_file(cur_file_path, new_file_path)
chmod_as_parent(new_file_path)
except (IOError, OSError) as e:
self._log("Unable to hardlink file {} to {}: {}".format(cur_file_path, new_file_path, e),
sickrage.app.log.WARNING)
raise
self._combined_file_operation(file_path, new_path, new_base_name, associated_files, action=_int_hard_link,
subs=subs)
def _moveAndSymlink(self, file_path, new_path, new_base_name, associated_files=False, subs=False):
"""
Move file, symlink source location back to destination, and set proper permissions
:param file_path: The full path of the media file to move
:param new_path: Destination path where we want to move the file to create a symbolic link to
:param new_base_name: The base filename (no extension) to use during the link. Use None to keep the same name.
:param associated_files: Boolean, whether we should move similarly-named files too
"""
def _int_move_and_sym_link(cur_file_path, new_file_path):
self._log("Moving then symbolic linking file from " + cur_file_path + " to " + new_file_path,
sickrage.app.log.DEBUG)
try:
move_and_symlink_file(cur_file_path, new_file_path)
chmod_as_parent(new_file_path)
except (IOError, OSError) as e:
self._log("Unable to move and symlink file {} to {}: {}".format(cur_file_path, new_file_path, e),
sickrage.app.log.WARNING)
raise
self._combined_file_operation(file_path, new_path, new_base_name, associated_files,
action=_int_move_and_sym_link, subs=subs)
def _symlink(self, file_path, new_path, new_base_name, associated_files=False, subtitles=False):
"""
symlink destination to source location, and set proper permissions
:param file_path: The full path of the media file to link
:param new_path: Destination path where we want to create a symbolic link to
:param new_base_name: The base filename (no extension) to use during the link. Use None to keep the same name.
:param associated_files: Boolean, whether we should move similarly-named files too
"""
def _int_sym_link(cur_file_path, new_file_path):
self._log("Creating the symbolic linking file from " + new_file_path + " to " + cur_file_path,
sickrage.app.log.DEBUG)
try:
if os.path.exists(new_file_path):
os.remove(new_file_path)
symlink(cur_file_path, new_file_path)
chmod_as_parent(cur_file_path)
except (IOError, OSError) as e:
self._log("Unable to symlink file {} to {}: {}".format(cur_file_path, new_file_path, e),
sickrage.app.log.WARNING)
raise
self._combined_file_operation(file_path, new_path, new_base_name, associated_files,
action=_int_sym_link, subs=subtitles)
def _history_lookup(self):
"""
Look up the NZB name in the history and see if it contains a record for self.nzb_name
:return: A (series_id, season, [], quality, version) tuple. The first two may be None if none were found.
"""
session = sickrage.app.main_db.session()
self.in_history = False
to_return = None, None, None, [], None, None, None
# if we don't have either of these then there's nothing to use to search the history for anyway
if not self.nzb_name and not self.file_name:
return to_return
# make a list of possible names to use in the search
names = []
if self.nzb_name:
names.append(self.nzb_name)
if '.' in self.nzb_name:
names.append(self.nzb_name.rpartition(".")[0])
if self.file_name:
names.append(self.file_name)
if '.' in self.file_name:
names.append(self.file_name.rpartition(".")[0])
# search the database for a possible match and return immediately if we find one
for curName in names:
dbData = session.query(MainDB.History).filter(MainDB.History.resource.contains(curName)).first()
if not dbData:
continue
series_id = dbData.series_id
series_provider_id = dbData.series_provider_id
season = dbData.season
episode = dbData.episode
quality = dbData.quality
version = dbData.version
release_group = dbData.release_group
if quality == Qualities.UNKNOWN:
quality = None
self.version = version
to_return = series_id, series_provider_id, season, [episode], quality, version, release_group
self._log(f"Found result in history for {curName} - Season: {season} - Episode: {episode} - Quality: {quality.display_name} - Version: {version}",
sickrage.app.log.DEBUG)
self.in_history = True
break
return to_return
def _finalize(self, parse_result):
"""
Store parse result if it is complete and final
:param parse_result: Result of parsers
"""
# remember whether it's a proper
if parse_result.extra_info:
self.is_proper = re.search(r'\b(proper|repack|real)\b', parse_result.extra_info, re.I) is not None
# if the result is complete then remember that for later
# if the result is complete then set release name
if parse_result.series_name and (
(parse_result.season_number is not None and parse_result.episode_numbers) or parse_result.air_date) and parse_result.release_group:
if not self.release_name:
self.release_name = remove_non_release_groups(remove_extension(os.path.basename(parse_result.original_name)))
else:
sickrage.app.log.debug("Parse result not sufficient (all following have to be set). will not save release name")
sickrage.app.log.debug("Parse result(series_name): " + str(parse_result.series_name))
sickrage.app.log.debug("Parse result(season_number): " + str(parse_result.season_number))
sickrage.app.log.debug("Parse result(episode_numbers): " + str(parse_result.episode_numbers))
sickrage.app.log.debug("Parse result(air_date): " + str(parse_result.air_date))
sickrage.app.log.debug("Parse result(release_group): " + str(parse_result.release_group))
def _analyze_name(self, name):
"""
Takes a name and tries to figure out a show, season, and episode from it.
:param name: A string which we want to analyze to determine show info from (unicode)
:return: A (series_id, season, [episodes]) tuple. The first two may be None and episodes may be []
if none were found.
"""
to_return = None, None, None, [], None, None, None
if not name:
return to_return
session = sickrage.app.main_db.session()
sickrage.app.log.debug("Analyzing name " + repr(name))
name = remove_non_release_groups(remove_extension(name))
# parse the name to break it into show name, season, and episode
parse_result = NameParser(True).parse(name)
season = None
episodes = []
if parse_result.is_air_by_date:
self._log("Looks like this is an air-by-date or sports show, attempting to convert the date to episode ID", sickrage.app.log.DEBUG)
try:
query = session.query(MainDB.TVEpisode).filter_by(series_id=parse_result.series_id,
series_provider_id=parse_result.series_provider_id,
airdate=parse_result.air_date).one()
season = query.season
episodes += [query.episode]
except orm.exc.MultipleResultsFound:
self._log("Found multiple episodes with date {} for show {} from series provider {}, please manually rename episode files to S##E## "
"equivalents then manual run post-process".format(parse_result.is_air_by_date, parse_result.series_id,
parse_result.series_provider_id), sickrage.app.log.DEBUG)
except orm.exc.NoResultFound:
self._log("Unable to find episode with date {} for show {} from series provider {}, skipping".format(parse_result.is_air_by_date,
parse_result.series_id,
parse_result.series_provider_id),
sickrage.app.log.DEBUG)
else:
for episode_number in parse_result.episode_numbers:
try:
query = session.query(MainDB.TVEpisode).filter_by(series_id=parse_result.series_id,
series_provider_id=parse_result.series_provider_id,
season=parse_result.season_number,
episode=episode_number).one()
season = query.season
episodes += [query.episode]
except orm.exc.NoResultFound:
continue
to_return = (parse_result.series_id, parse_result.series_provider_id, season, episodes, parse_result.quality, None, parse_result.release_group)
self._finalize(parse_result)
return to_return
def _add_to_anidb_mylist(self, filePath):
"""
Adds an episode to anidb mylist
:param filePath: file to add to mylist
"""
if not self.anidbEpisode: # seems like we could parse the name before, now lets build the anidb object
self.anidbEpisode = get_anime_episode(filePath)
if self.anidbEpisode:
self._log("Adding the file to the AniDB MyList", sickrage.app.log.DEBUG)
try:
# state of 1 sets the state of the file to "internal HDD"
self.anidbEpisode.add_to_mylist(state=1)
except Exception as e:
sickrage.app.log.debug('Exception message: {0!r}'.format(e))
def _find_info(self):
"""
For a given file try to find the series_id, season, and episode.
:return: A (series_id, season, episode, quality, version) tuple
"""
series_id = None
series_provider_id = None
quality = None
version = None
release_group = None
season = None
episodes = []
# try to look up the nzb in history
attempt_list = [
self._history_lookup,
# try to analyze the nzb name
lambda: self._analyze_name(self.nzb_name),
# try to analyze the file name
lambda: self._analyze_name(self.file_name),
# try to analyze the dir name
lambda: self._analyze_name(self.folder_name),
# try to analyze the file + dir names together
lambda: self._analyze_name(self.file_path),
# try to analyze the dir + file name together as one name
lambda: self._analyze_name(self.folder_name + ' ' + self.file_name)
]
# attempt every possible method to get our info
for cur_attempt in attempt_list:
try:
(cur_show_id, cur_series_provider_id, cur_season, cur_episodes, cur_quality, cur_version, cur_release_group) = cur_attempt()
except (InvalidNameException, InvalidShowException) as e:
sickrage.app.log.debug("Unable to parse, skipping: {}".format(e))
continue
if not cur_show_id or not cur_series_provider_id:
continue
series_id = cur_show_id
series_provider_id = cur_series_provider_id
if cur_season is not None:
season = cur_season
if len(cur_episodes):
episodes = cur_episodes
if cur_quality and not (self.in_history and quality):
quality = cur_quality
# we only get current version for animes from history to prevent issues with old database entries
if cur_version is not None:
version = cur_version
if cur_release_group is not None:
release_group = cur_release_group
if all([series_id, series_provider_id, season is not None, len(episodes) > 0, quality]):
break
return series_id, series_provider_id, season, sorted(episodes), quality, version, release_group
def _get_quality(self, ep_obj):
"""
Determines the quality of the file that is being post processed, first by checking if it is directly
available in the TVEpisode's status or otherwise by parsing through the data available.
:param ep_obj: The TVEpisode object related to the file we are post processing
:return: A quality value found in Quality
"""
# if there is a quality available in the status then we don't need to bother guessing from the filename
if ep_obj.status in flatten([EpisodeStatus.composites(EpisodeStatus.SNATCHED), EpisodeStatus.composites(EpisodeStatus.SNATCHED_PROPER),
EpisodeStatus.composites(EpisodeStatus.SNATCHED_BEST)]):
__, ep_quality = Quality.split_composite_status(ep_obj.status)
if ep_quality != Qualities.UNKNOWN:
self._log("The old status had a quality in it, using that: " + ep_quality.display_name, sickrage.app.log.DEBUG)
return ep_quality
# nzb name is the most reliable if it exists, followed by folder name and lastly file name
name_list = [self.nzb_name, self.folder_name, self.file_name]
# search all possible names for our new quality, in case the file or dir doesn't have it
for cur_name in name_list:
# some stuff might be None at this point still
if not cur_name:
continue
ep_quality = Quality.name_quality(cur_name, ep_obj.show.is_anime)
self._log("Looking up quality for name " + cur_name + ", got " + ep_quality.display_name, sickrage.app.log.DEBUG)
# if we find a good one then use it
if ep_quality != Qualities.UNKNOWN:
sickrage.app.log.debug(cur_name + " looks like it has quality " + ep_quality.display_name + ", using that")
return ep_quality
# Try getting quality from the episode (snatched) status
if ep_obj.status in flatten([EpisodeStatus.composites(EpisodeStatus.SNATCHED), EpisodeStatus.composites(EpisodeStatus.SNATCHED_PROPER),
EpisodeStatus.composites(EpisodeStatus.SNATCHED_BEST)]):
__, ep_quality = Quality.split_composite_status(ep_obj.status)
if ep_quality != Qualities.UNKNOWN:
self._log("The old status had a quality in it, using that: " + ep_quality.display_name, sickrage.app.log.DEBUG)
return ep_quality
# Try guessing quality from the file name
ep_quality = Quality.name_quality(self.file_path)
self._log("Guessing quality for name " + self.file_name + ", got " + ep_quality.display_name, sickrage.app.log.DEBUG)
if ep_quality != Qualities.UNKNOWN:
sickrage.app.log.debug(self.file_name + " looks like it has quality " + ep_quality.display_name + ", using that")
return ep_quality
def _run_extra_scripts(self, ep_obj):
"""
Executes any extra scripts defined in the config.
:param ep_obj: The object to use when calling the extra script
"""
for curScriptName in [x for x in sickrage.app.config.general.extra_scripts.split('|') if x]:
# generate a safe command line string to execute the script and provide all the parameters
script_cmd = [piece for piece in re.split("( |\\\".*?\\\"|'.*?')", curScriptName) if piece.strip()]
script_cmd[0] = os.path.abspath(script_cmd[0])
self._log("Absolute path to script: " + script_cmd[0], sickrage.app.log.DEBUG)
script_cmd = script_cmd + [ep_obj.location, self.file_path, str(ep_obj.show.series_id), str(ep_obj.season),
str(ep_obj.episode), str(ep_obj.airdate)]
# use subprocess to run the command and capture output
self._log("Executing command " + str(script_cmd))
try:
p = subprocess.Popen(script_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, cwd=sickrage.PROG_DIR)
out, __ = p.communicate()
self._log("Script result: " + str(out), sickrage.app.log.DEBUG)
except OSError as e:
self._log("Unable to run extra_script: {}".format(e))
except Exception as e:
self._log("Unable to run extra_script: {}".format(e))
def _is_priority(self, ep_obj, new_ep_quality):
"""
Determines if the episode is a priority download or not (if it is expected). Episodes which are expected
(snatched) or larger than the existing episode are priority, others are not.
:param ep_obj: The TVEpisode object in question
:param new_ep_quality: The quality of the episode that is being processed
:return: True if the episode is priority, False otherwise.
"""
if self.is_priority:
return True
__, old_ep_quality = Quality.split_composite_status(ep_obj.status)
# if SR downloaded this on purpose we likely have a priority download
if self.in_history or ep_obj.status in flatten(
[EpisodeStatus.composites(EpisodeStatus.SNATCHED), EpisodeStatus.composites(EpisodeStatus.SNATCHED_PROPER),
EpisodeStatus.composites(EpisodeStatus.SNATCHED_BEST)]):
# if the episode is still in a snatched status, then we can assume we want this
if not self.in_history:
self._log("SR snatched this episode and it is not processed before", sickrage.app.log.DEBUG)
return True
# if it's in history, we only want it if the new quality is higher or if it's a proper of equal or higher
# quality
if new_ep_quality > old_ep_quality and new_ep_quality != Qualities.UNKNOWN:
self._log("SR snatched this episode and it is a higher quality so I'm marking it as priority",
sickrage.app.log.DEBUG)
return True
if self.is_proper and new_ep_quality >= old_ep_quality and new_ep_quality != Qualities.UNKNOWN:
self._log("SR snatched this episode and it is a proper of equal or higher quality so I'm marking it "
"as priority", sickrage.app.log.DEBUG)
return True
return False
# if the user downloaded it manually and it's higher quality than the existing episode then it's priority
if new_ep_quality > old_ep_quality and new_ep_quality != Qualities.UNKNOWN:
self._log("This was manually downloaded but it appears to be better quality than what we have so I'm "
"marking it as priority", sickrage.app.log.DEBUG)
return True
# if the user downloaded it manually and it appears to be a PROPER/REPACK then it's priority
if self.is_proper and new_ep_quality >= old_ep_quality and new_ep_quality != Qualities.UNKNOWN:
self._log("This was manually downloaded but it appears to be a proper so I'm marking it as priority",
sickrage.app.log.DEBUG)
return True
return False
def _add_processed_marker_file(self, file_path):
touch_file(file_path + '.sr_processed')
def process(self):
"""
Post-process a given file
:return: True on success, False on failure
"""
self._log("Processing file {}".format(self.file_path))
if os.path.isdir(self.file_path):
self._log("File %s seems to be a directory" % self.file_path)
return False
if not os.path.exists(self.file_path):
self._log("File %s doesn't exist, did unrar fail?" % self.file_path)
return False
for ignore_file in self.IGNORED_FILESTRINGS:
if ignore_file in self.file_path:
self._log("File %s is ignored type, skipping" % self.file_path)
return False
# reset per-file stuff
self.in_history = False
# reset the anidb episode object
self.anidbEpisode = None
# try to find the file info
series_id, series_provider_id, season, episodes, quality, version, release_group = self._find_info()
show_object = find_show(series_id, series_provider_id)
if not show_object:
self._log("This show isn't in your list, you need to add it to SiCKRAGE before post-processing an episode")
raise EpisodePostProcessingFailedException()
elif season is None or not len(episodes):
self._log("Not enough information to determine what season/episode this is. Quitting post-processing")
return False
episode_objects = sorted([show_object.get_episode(season=season, episode=x) for x in episodes], key=lambda k: k.episode)
root_episode_object = episode_objects[0]
self._log("Retrieving episode object for {}x{}".format(root_episode_object.season, root_episode_object.episode), sickrage.app.log.DEBUG)
__, old_ep_quality = Quality.split_composite_status(root_episode_object.status)
# get the quality of the episode we're processing
if quality and not quality == Qualities.UNKNOWN:
self._log("Snatch history had a quality in it, using that: " + quality.display_name, sickrage.app.log.DEBUG)
new_ep_quality = quality
else:
new_ep_quality = self._get_quality(root_episode_object)
sickrage.app.log.debug("Quality of the episode we're processing: %s" % new_ep_quality)
# see if this is a priority download (is it snatched, in history, PROPER, or BEST)
priority_download = self._is_priority(root_episode_object, new_ep_quality)
self._log("Is ep a priority download: " + str(priority_download), sickrage.app.log.DEBUG)
# get the version of the episode we're processing
new_ep_version = -1
if version:
self._log("Snatch history had a version in it, using that: v" + str(version), sickrage.app.log.DEBUG)
new_ep_version = version
# check for an existing file
existing_file_status = self._checkForExistingFile(root_episode_object.location)
# if it's not priority then we don't want to replace smaller files in case it was a mistake
if not priority_download:
# Not a priority and the quality is lower than what we already have
if (new_ep_quality < old_ep_quality != Qualities.UNKNOWN) and not existing_file_status == PostProcessor.DOESNT_EXIST:
self._log("File exists and new file quality is lower than existing, marking it unsafe to replace")
return False
# if there's an existing file that we don't want to replace stop here
if existing_file_status == PostProcessor.EXISTS_LARGER:
if self.is_proper:
self._log("File exists and new file is smaller, new file is a proper/repack, marking it safe to replace")
return True
else:
self._log("File exists and new file is smaller, marking it unsafe to replace")
return False
elif existing_file_status == PostProcessor.EXISTS_SAME:
self._log("File exists and new file is same size, marking it unsafe to replace")
return False
# if the file is priority then we're going to replace it even if it exists
else:
self._log("This download is marked a priority download so I'm going to replace an existing file if I find one")
# try to find out if we have enough space to perform the copy or move action.
if not is_file_locked(self.file_path, False):
if not verify_freespace(self.file_path, show_object.location, episode_objects):
self._log("Not enough space to continue PostProcessing, exiting", sickrage.app.log.WARNING)
raise NoFreeSpaceException
else:
self._log("Unable to determine needed filespace as the source file is locked for access")
# delete the existing file (and company)
for cur_ep in episode_objects:
try:
self._delete(cur_ep.location, associated_files=True)
# clean up any left over folders
if cur_ep.location:
delete_empty_folders(os.path.dirname(cur_ep.location), keep_dir=show_object.location)
except (OSError, IOError):
raise EpisodePostProcessingFailedException("Unable to delete the existing files")
# set the status of the episodes
# for curEp in [ep_obj] + ep_obj.related_episodes:
# curEp.status = Quality.compositeStatus(SNATCHED, new_ep_quality)
# if the show directory doesn't exist then make it if allowed
if not os.path.isdir(show_object.location) and sickrage.app.config.general.create_missing_show_dirs:
self._log("Show directory doesn't exist, creating it", sickrage.app.log.DEBUG)
try:
os.mkdir(show_object.location)
chmod_as_parent(show_object.location)
# do the library update for synoindex
sickrage.app.notification_providers['synoindex'].addFolder(show_object.location)
except (OSError, IOError):
raise EpisodePostProcessingFailedException("Unable to create the show directory: " + show_object.location)
# write metadata for the show (but not episode because it hasn't been fully processed)
show_object.write_metadata(True)
# find the destination folder
if not os.path.isdir(show_object.location):
raise EpisodePostProcessingFailedException("Unable to post-process an episode if the show dir doesn't exist, quitting")
# update the ep info before we rename so the quality & release name go into the name properly
for cur_ep in episode_objects:
if self.release_name:
self._log("Found release name " + self.release_name, sickrage.app.log.DEBUG)
cur_ep.release_name = self.release_name
else:
cur_ep.release_name = ""
if root_episode_object.status in EpisodeStatus.composites(EpisodeStatus.SNATCHED_BEST):
cur_ep.status = Quality.composite_status(EpisodeStatus.ARCHIVED, new_ep_quality)
else:
cur_ep.status = Quality.composite_status(EpisodeStatus.DOWNLOADED, new_ep_quality)
cur_ep.subtitles = ''
cur_ep.subtitles_searchcount = 0
cur_ep.subtitles_lastsearch = datetime.datetime.min
cur_ep.is_proper = self.is_proper
cur_ep.version = new_ep_version
cur_ep.release_group = release_group or ""
cur_ep.location = self.file_path
# Just want to keep this consistent for failed handling right now
release_name = show_names.determine_release_name(self.folder_path, self.nzb_name)
if release_name is not None:
FailedHistory.log_success(release_name)
else:
self._log("Couldn't find release in snatch history", sickrage.app.log.WARNING)
proper_path = root_episode_object.proper_path()
proper_absolute_path = os.path.join(show_object.location, proper_path)
dest_path = os.path.dirname(proper_absolute_path)
self._log("Destination folder for this episode: " + dest_path, sickrage.app.log.DEBUG)
# create any folders we need
make_dirs(dest_path)
# figure out the base name of the resulting episode file
if sickrage.app.config.general.rename_episodes:
orig_extension = self.file_name.rpartition('.')[-1]
new_base_name = os.path.basename(proper_path)
new_file_name = "{}.{}".format(new_base_name, orig_extension)
else:
# if we're not renaming then there's no new base name, we'll just use the existing name
new_base_name = None
new_file_name = self.file_name
# add to anidb
if show_object.is_anime and sickrage.app.config.anidb.use_my_list:
self._add_to_anidb_mylist(self.file_path)
try:
# move the episode and associated files to the show dir
if self.process_method == ProcessMethod.COPY:
if is_file_locked(self.file_path, False):
raise EpisodePostProcessingFailedException("File is locked for reading")
self._copy(self.file_path, dest_path, new_base_name, sickrage.app.config.general.move_associated_files,
sickrage.app.config.subtitles.enable and show_object.subtitles)
elif self.process_method == ProcessMethod.MOVE:
if is_file_locked(self.file_path, True):
raise EpisodePostProcessingFailedException("File is locked for reading/writing")
self._move(self.file_path, dest_path, new_base_name, sickrage.app.config.general.move_associated_files,
sickrage.app.config.subtitles.enable and show_object.subtitles)
elif self.process_method == ProcessMethod.HARDLINK:
self._hardlink(self.file_path, dest_path, new_base_name, sickrage.app.config.general.move_associated_files,
sickrage.app.config.subtitles.enable and show_object.subtitles)
elif self.process_method == ProcessMethod.SYMLINK:
if is_file_locked(self.file_path, True):
raise EpisodePostProcessingFailedException("File is locked for reading/writing")
self._moveAndSymlink(self.file_path, dest_path, new_base_name,
sickrage.app.config.general.move_associated_files,
sickrage.app.config.subtitles.enable and show_object.subtitles)
elif self.process_method == ProcessMethod.SYMLINK_REVERSED:
self._symlink(self.file_path, dest_path, new_base_name, sickrage.app.config.general.move_associated_files,
sickrage.app.config.subtitles.enable and show_object.subtitles)
except (OSError, IOError):
raise EpisodePostProcessingFailedException("Unable to move the files to their new home")
# add processed marker file
self._add_processed_marker_file(self.file_path)
# download subtitles
if sickrage.app.config.subtitles.enable and show_object.subtitles:
for cur_ep in episode_objects:
cur_ep.location = os.path.join(dest_path, new_file_name)
cur_ep.refresh_subtitles()
cur_ep.download_subtitles()
# put the new location in the database
for cur_ep in episode_objects:
cur_ep.location = os.path.join(dest_path, new_file_name)
# set file modify stamp to show airdate
if sickrage.app.config.general.airdate_episodes:
for cur_ep in episode_objects:
cur_ep.airdate_modify_stamp()
# generate nfo/tbn
root_episode_object.create_meta_files()
# update video file metadata
if sickrage.app.config.general.update_video_metadata:
root_episode_object.update_video_metadata()
# save changes to database
[cur_ep.save() for cur_ep in episode_objects]
# log it to history
History.log_download(
root_episode_object.series_id,
root_episode_object.series_provider_id,
root_episode_object.season,
root_episode_object.episode,
root_episode_object.status,
self.file_path,
new_ep_quality,
release_group,
new_ep_version
)
# If any notification fails, don't stop postProcessor
try:
# send notifications
NotificationProvider.mass_notify_download(root_episode_object._format_pattern('%SN - %Sx%0E - %EN - %QN'))
# do the library update for KODI
sickrage.app.notification_providers['kodi'].update_library(show_object.name)
# do the library update for Plex
sickrage.app.notification_providers['plex'].update_library(root_episode_object)
# do the library update for EMBY
sickrage.app.notification_providers['emby'].update_library(show_object)
# do the library update for NMJ
# nmj_notifier kicks off its library update when the notify_download is issued (inside notifiers)
# do the library update for Synology Indexer
sickrage.app.notification_providers['synoindex'].addFile(root_episode_object.location)
# do the library update for pyTivo
sickrage.app.notification_providers['pytivo'].update_library(root_episode_object)
# do the library update for Trakt
sickrage.app.notification_providers['trakt'].update_library(root_episode_object)
except Exception:
sickrage.app.log.info("Some notifications could not be sent. Continuing with post-processing...")
self._run_extra_scripts(root_episode_object)
return True
================================================
FILE: sickrage/core/queues/__init__.py
================================================
# Author: echel0n
# URL: https://sickrage.ca
# Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
#
# This file is part of SiCKRAGE.
#
# SiCKRAGE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SiCKRAGE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SiCKRAGE. If not, see