Compare commits

..

3 Commits

Author SHA1 Message Date
Taloth Saldono 40b34dbb5e Do custom gzip compression on mono when returning api responses to avoid a memory leak. 2019-01-08 20:34:35 +01:00
Taloth Saldono 567719e6c4 Only do the custom decompression on mono. 2019-01-08 20:33:50 +01:00
Taloth Saldono 76212ef908 Do our own decompression to workaround mono bug. 2019-01-04 23:29:32 +01:00
4902 changed files with 124024 additions and 197943 deletions

View File

@ -1,13 +0,0 @@
// This file is used to open the backend and frontend in the same workspace, which is necessary as
// the frontend has vscode settings that are distinct from the backend
{
"folders": [
{
"path": ".."
},
{
"path": "../frontend"
}
],
"settings": {}
}

View File

@ -1,19 +0,0 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet
{
"name": "Sonarr",
"image": "mcr.microsoft.com/devcontainers/dotnet:1-6.0",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"nodeGypDependencies": true,
"version": "16",
"nvmVersion": "latest"
}
},
"forwardPorts": [8989],
"customizations": {
"vscode": {
"extensions": ["esbenp.prettier-vscode"]
}
}
}

View File

@ -2,274 +2,14 @@
# editorconfig.org
root = true
# NOTE: Requires **VS2019 16.3** or later
# Stylecop.ruleset
# Description: Rules for Sonarr
# Code files
[*.cs]
[*.{cs}]
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 4
# Sort using and Import directives with System.* appearing first
dotnet_sort_system_directives_first = true
# Avoid "this." and "Me." if not necessary
dotnet_style_qualification_for_field = false:refactoring
dotnet_style_qualification_for_property = false:refactoring
dotnet_style_qualification_for_method = false:refactoring
dotnet_style_qualification_for_event = false:refactoring
# Indentation preferences
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion
dotnet_naming_style.instance_field_style.capitalization = camel_case
dotnet_naming_style.instance_field_style.required_prefix = _
# Prefer "var" everywhere
csharp_style_var_for_built_in_types = true
csharp_style_var_when_type_is_apparent = true
csharp_style_var_elsewhere = true
# Prefer "out" variables to be declared inline
csharp_style_inlined_variable_declaration = true
# Using directive is unnecessary.
dotnet_diagnostic.IDE0005.severity = error
# Use var instead of explicit type
dotnet_diagnostic.IDE0007.severity = error
# Inline variable declaration
dotnet_diagnostic.IDE0018.severity = error
# Stylecop Rules
dotnet_diagnostic.SA0001.severity = none
dotnet_diagnostic.SA1025.severity = none
dotnet_diagnostic.SA1101.severity = none
dotnet_diagnostic.SA1116.severity = none
dotnet_diagnostic.SA1118.severity = none
dotnet_diagnostic.SA1122.severity = none
dotnet_diagnostic.SA1201.severity = suggestion
dotnet_diagnostic.SA1202.severity = suggestion
dotnet_diagnostic.SA1204.severity = suggestion
dotnet_diagnostic.SA1300.severity = none
dotnet_diagnostic.SA1303.severity = none
dotnet_diagnostic.SA1304.severity = none
dotnet_diagnostic.SA1306.severity = none
dotnet_diagnostic.SA1309.severity = none
dotnet_diagnostic.SA1310.severity = none
dotnet_diagnostic.SA1401.severity = none
dotnet_diagnostic.SA1402.severity = none
dotnet_diagnostic.SA1404.severity = suggestion
dotnet_diagnostic.SA1405.severity = suggestion
dotnet_diagnostic.SA1406.severity = suggestion
dotnet_diagnostic.SA1410.severity = suggestion
dotnet_diagnostic.SA1411.severity = suggestion
dotnet_diagnostic.SA1413.severity = none
dotnet_diagnostic.SA1512.severity = none
dotnet_diagnostic.SA1516.severity = none
dotnet_diagnostic.SA1600.severity = none
dotnet_diagnostic.SA1601.severity = none
dotnet_diagnostic.SA1602.severity = none
dotnet_diagnostic.SA1604.severity = none
dotnet_diagnostic.SA1605.severity = none
dotnet_diagnostic.SA1606.severity = none
dotnet_diagnostic.SA1607.severity = none
dotnet_diagnostic.SA1608.severity = none
dotnet_diagnostic.SA1610.severity = none
dotnet_diagnostic.SA1611.severity = none
dotnet_diagnostic.SA1612.severity = none
dotnet_diagnostic.SA1613.severity = none
dotnet_diagnostic.SA1614.severity = none
dotnet_diagnostic.SA1615.severity = none
dotnet_diagnostic.SA1616.severity = none
dotnet_diagnostic.SA1617.severity = none
dotnet_diagnostic.SA1618.severity = none
dotnet_diagnostic.SA1619.severity = none
dotnet_diagnostic.SA1620.severity = none
dotnet_diagnostic.SA1621.severity = none
dotnet_diagnostic.SA1622.severity = none
dotnet_diagnostic.SA1623.severity = none
dotnet_diagnostic.SA1624.severity = none
dotnet_diagnostic.SA1625.severity = none
dotnet_diagnostic.SA1626.severity = none
dotnet_diagnostic.SA1627.severity = none
dotnet_diagnostic.SA1629.severity = none
dotnet_diagnostic.SA1633.severity = none
dotnet_diagnostic.SA1634.severity = none
dotnet_diagnostic.SA1635.severity = none
dotnet_diagnostic.SA1636.severity = none
dotnet_diagnostic.SA1637.severity = none
dotnet_diagnostic.SA1638.severity = none
dotnet_diagnostic.SA1640.severity = none
dotnet_diagnostic.SA1641.severity = none
dotnet_diagnostic.SA1642.severity = none
dotnet_diagnostic.SA1643.severity = none
dotnet_diagnostic.SA1648.severity = none
dotnet_diagnostic.SA1649.severity = none
dotnet_diagnostic.SA1651.severity = none
dotnet_diagnostic.SX1309.severity = warning
# Microsoft Analyzers that fail and need to be sorted thru
dotnet_diagnostic.ASP0000.severity = suggestion
dotnet_diagnostic.CA1000.severity = suggestion
dotnet_diagnostic.CA1001.severity = suggestion
dotnet_diagnostic.CA1002.severity = suggestion
dotnet_diagnostic.CA1003.severity = suggestion
dotnet_diagnostic.CA1008.severity = suggestion
dotnet_diagnostic.CA1010.severity = suggestion
dotnet_diagnostic.CA1012.severity = suggestion
dotnet_diagnostic.CA1014.severity = suggestion
dotnet_diagnostic.CA1016.severity = suggestion
dotnet_diagnostic.CA1017.severity = suggestion
dotnet_diagnostic.CA1018.severity = suggestion
dotnet_diagnostic.CA1019.severity = suggestion
dotnet_diagnostic.CA1021.severity = suggestion
dotnet_diagnostic.CA1024.severity = suggestion
dotnet_diagnostic.CA1027.severity = suggestion
dotnet_diagnostic.CA1028.severity = suggestion
dotnet_diagnostic.CA1030.severity = suggestion
dotnet_diagnostic.CA1031.severity = suggestion
dotnet_diagnostic.CA1032.severity = suggestion
dotnet_diagnostic.CA1033.severity = suggestion
dotnet_diagnostic.CA1034.severity = suggestion
dotnet_diagnostic.CA1036.severity = suggestion
dotnet_diagnostic.CA1040.severity = suggestion
dotnet_diagnostic.CA1041.severity = suggestion
dotnet_diagnostic.CA1043.severity = suggestion
dotnet_diagnostic.CA1044.severity = suggestion
dotnet_diagnostic.CA1050.severity = suggestion
dotnet_diagnostic.CA1051.severity = suggestion
dotnet_diagnostic.CA1052.severity = suggestion
dotnet_diagnostic.CA1054.severity = suggestion
dotnet_diagnostic.CA1055.severity = suggestion
dotnet_diagnostic.CA1056.severity = suggestion
dotnet_diagnostic.CA1058.severity = suggestion
dotnet_diagnostic.CA1060.severity = suggestion
dotnet_diagnostic.CA1061.severity = suggestion
dotnet_diagnostic.CA1062.severity = suggestion
dotnet_diagnostic.CA1063.severity = suggestion
dotnet_diagnostic.CA1064.severity = suggestion
dotnet_diagnostic.CA1065.severity = suggestion
dotnet_diagnostic.CA1066.severity = suggestion
dotnet_diagnostic.CA1067.severity = suggestion
dotnet_diagnostic.CA1068.severity = suggestion
dotnet_diagnostic.CA1069.severity = suggestion
dotnet_diagnostic.CA1200.severity = suggestion
dotnet_diagnostic.CA1303.severity = suggestion
dotnet_diagnostic.CA1304.severity = suggestion
dotnet_diagnostic.CA1305.severity = suggestion
dotnet_diagnostic.CA1307.severity = suggestion
dotnet_diagnostic.CA1308.severity = suggestion
dotnet_diagnostic.CA1309.severity = suggestion
dotnet_diagnostic.CA1310.severity = suggestion
dotnet_diagnostic.CA1401.severity = suggestion
dotnet_diagnostic.CA1416.severity = suggestion
dotnet_diagnostic.CA1419.severity = suggestion
dotnet_diagnostic.CA1507.severity = suggestion
dotnet_diagnostic.CA1508.severity = suggestion
dotnet_diagnostic.CA1707.severity = suggestion
dotnet_diagnostic.CA1708.severity = suggestion
dotnet_diagnostic.CA1710.severity = suggestion
dotnet_diagnostic.CA1711.severity = suggestion
dotnet_diagnostic.CA1712.severity = suggestion
dotnet_diagnostic.CA1714.severity = suggestion
dotnet_diagnostic.CA1715.severity = suggestion
dotnet_diagnostic.CA1716.severity = suggestion
dotnet_diagnostic.CA1717.severity = suggestion
dotnet_diagnostic.CA1720.severity = suggestion
dotnet_diagnostic.CA1721.severity = suggestion
dotnet_diagnostic.CA1724.severity = suggestion
dotnet_diagnostic.CA1725.severity = suggestion
dotnet_diagnostic.CA1806.severity = suggestion
dotnet_diagnostic.CA1810.severity = suggestion
dotnet_diagnostic.CA1812.severity = suggestion
dotnet_diagnostic.CA1813.severity = suggestion
dotnet_diagnostic.CA1814.severity = suggestion
dotnet_diagnostic.CA1815.severity = suggestion
dotnet_diagnostic.CA1816.severity = suggestion
dotnet_diagnostic.CA1819.severity = suggestion
dotnet_diagnostic.CA1822.severity = suggestion
dotnet_diagnostic.CA1823.severity = suggestion
dotnet_diagnostic.CA1824.severity = suggestion
dotnet_diagnostic.CA1825.severity = suggestion
dotnet_diagnostic.CA2000.severity = suggestion
dotnet_diagnostic.CA2002.severity = suggestion
dotnet_diagnostic.CA2007.severity = suggestion
dotnet_diagnostic.CA2008.severity = suggestion
dotnet_diagnostic.CA2012.severity = suggestion
dotnet_diagnostic.CA2013.severity = suggestion
dotnet_diagnostic.CA2100.severity = suggestion
dotnet_diagnostic.CA2101.severity = suggestion
dotnet_diagnostic.CA2119.severity = suggestion
dotnet_diagnostic.CA2153.severity = suggestion
dotnet_diagnostic.CA2200.severity = suggestion
dotnet_diagnostic.CA2201.severity = suggestion
dotnet_diagnostic.CA2207.severity = suggestion
dotnet_diagnostic.CA2208.severity = suggestion
dotnet_diagnostic.CA2211.severity = suggestion
dotnet_diagnostic.CA2213.severity = suggestion
dotnet_diagnostic.CA2214.severity = suggestion
dotnet_diagnostic.CA2215.severity = suggestion
dotnet_diagnostic.CA2216.severity = suggestion
dotnet_diagnostic.CA2219.severity = suggestion
dotnet_diagnostic.CA2225.severity = suggestion
dotnet_diagnostic.CA2226.severity = suggestion
dotnet_diagnostic.CA2227.severity = suggestion
dotnet_diagnostic.CA2229.severity = suggestion
dotnet_diagnostic.CA2231.severity = suggestion
dotnet_diagnostic.CA2234.severity = suggestion
dotnet_diagnostic.CA2235.severity = suggestion
dotnet_diagnostic.CA2237.severity = suggestion
dotnet_diagnostic.CA2241.severity = suggestion
dotnet_diagnostic.CA2242.severity = suggestion
dotnet_diagnostic.CA2243.severity = suggestion
dotnet_diagnostic.CA2244.severity = suggestion
dotnet_diagnostic.CA2245.severity = suggestion
dotnet_diagnostic.CA2246.severity = suggestion
dotnet_diagnostic.CA2249.severity = suggestion
dotnet_diagnostic.CA2251.severity = suggestion
dotnet_diagnostic.CA3061.severity = suggestion
dotnet_diagnostic.CA3075.severity = suggestion
dotnet_diagnostic.CA3076.severity = suggestion
dotnet_diagnostic.CA3077.severity = suggestion
dotnet_diagnostic.CA3147.severity = suggestion
dotnet_diagnostic.CA5350.severity = suggestion
dotnet_diagnostic.CA5351.severity = suggestion
dotnet_diagnostic.CA5359.severity = suggestion
dotnet_diagnostic.CA5360.severity = suggestion
dotnet_diagnostic.CA5363.severity = suggestion
dotnet_diagnostic.CA5364.severity = suggestion
dotnet_diagnostic.CA5365.severity = suggestion
dotnet_diagnostic.CA5366.severity = suggestion
dotnet_diagnostic.CA5368.severity = suggestion
dotnet_diagnostic.CA5369.severity = suggestion
dotnet_diagnostic.CA5370.severity = suggestion
dotnet_diagnostic.CA5371.severity = suggestion
dotnet_diagnostic.CA5372.severity = suggestion
dotnet_diagnostic.CA5373.severity = suggestion
dotnet_diagnostic.CA5374.severity = suggestion
dotnet_diagnostic.CA5379.severity = suggestion
dotnet_diagnostic.CA5384.severity = suggestion
dotnet_diagnostic.CA5385.severity = suggestion
dotnet_diagnostic.CA5392.severity = suggestion
dotnet_diagnostic.CA5394.severity = suggestion
dotnet_diagnostic.CA5397.severity = suggestion
dotnet_diagnostic.SYSLIB0006.severity = none
[*.{js,html,hbs,less,css,ts,tsx}]
[*.{js,html,js,hbs,less}]
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

9
.esprintrc Normal file
View File

@ -0,0 +1,9 @@
{
"paths": [
"frontend/src/**/*.js"
],
"ignored": [
"**/node_modules/**/*"
],
"port": 5004
}

24
.gitattributes vendored
View File

@ -1,12 +1,22 @@
# Auto detect text files and perform LF normalization
* text=auto
# Explicitly set bash scripts to have unix endings
# when checked out on windows
*.sh text eol=lf
distribution/debian/* text eol=lf
distribution/osx/Sonarr text eol=lf
*text eol=lf
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

41
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,41 @@
<!--
Before opening a new issue, please ensure:
- You use the forums for support/questions
- You search for existing bugs/feature requests
- Remove extraneous template details
- Do not prefix title with type of issue (Feature Request, Bug, etc.) The appropriate labels will be added during triage.
-->
## Support / Questions
Please use https://forums.sonarr.tv/ for support. Support requests or questions will be redirected to the forums and the issue will be closed.
<!--
Remove if not opening a bug report
-->
## Bug Report
### System Information/Logs
**Sonarr Version:**
**Operating System:**
**.net Framework (Windows) or mono (macOS/Linux) Version:**
**Link to Log Files (debug or trace):**
**Browser (for UI bugs):**
### Additional Information
<!--
Remove if not opening a feature request
-->
## Feature Request
### What problem are you looking to solve?
### Other Information

28
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,28 @@
---
name: Bug report
about: Create a report to help us improve Sonarr
---
**Describe the bug**
A clear and concise description of what the bug is.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Logs**
Link to debug or trace log files.
**System Information**
- Sonarr Version: [e.g. 2.0.0.1]
- Operating System: [e.g. Windows 10]
- .net Framework (Windows) or mono (macOS/Linux) Version: [e.g. 4.5 or 5.12]
**UI Bugs:**
- OS: [e.g. Windows]
- Browser: [e.g. chrome, firefox]
- Version: [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@ -1,81 +0,0 @@
name: Bug Report
description: 'Only bug reports for v4 will be accepted, older versions are no longer receiving bug fixes and support issues will be closed immediately.'
labels: ['needs-triage']
body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an open or closed issue already exists for the bug you encountered. If a bug exists and it is closed as complete it may not yet be in a stable release.
options:
- label: I have searched the existing open and closed issues
required: true
- type: textarea
attributes:
label: Current Behavior
description: A concise description of what you're experiencing.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: A concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Steps To Reproduce
description: Steps to reproduce the behavior.
placeholder: |
1. In this environment...
2. With this config...
3. Run '...'
4. See error...
validations:
required: false
- type: textarea
attributes:
label: Environment
description: |
examples:
- **OS**: Ubuntu 22.04
- **Sonarr**: Sonarr 4.0.0.766
- **Docker Install**: Yes
- **Using Reverse Proxy**: No
- **Browser**: Firefox 90 (If UI related)
- **Database**: Sqlite 3.41.2
value: |
- OS:
- Sonarr:
- Docker Install:
- Using Reverse Proxy:
- Browser:
- Database:
render: markdown
validations:
required: true
- type: dropdown
attributes:
label: What branch are you running?
options:
- Main
- Develop
- Other (This issue will be closed)
validations:
required: true
- type: textarea
attributes:
label: Trace Logs?
description: |
Trace Logs (https://wiki.servarr.com/sonarr/troubleshooting#logging-and-log-files)
***Generally speaking, all bug reports must have trace logs provided.***
*** Info Logs are not trace logs. If the logs do not say trace and are not from a file like `*.trace.*.txt` they are not trace logs.***
validations:
required: true
- type: textarea
attributes:
label: Anything else?
description: |
Links? Screenshots? References? Anything that will give us more context about the issue you are encountering!
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: false

View File

@ -1,14 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Support via Discord
url: https://discord.gg/M6BvZn5
about: Chat with users and devs on support and setup related topics.
- name: Support via Reddit
url: https://reddit.com/r/Sonarr
about: Discuss and search through support topics.
- name: Support via Forums
url: https://forums.sonarr.tv/
about: Discuss and search through support topics.
- name: Support via IRC
url: https://web.libera.chat/?channels=#sonarr
about: Chat with users and devs on support and setup related topics.

View File

@ -0,0 +1,14 @@
---
name: Feature request
about: Suggest an idea for Sonarr
---
**Describe the problem**
A clear and concise description of the problem you're looking to solve.
**Describe any solutions you think might work**
A clear and concise description of any solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -1,37 +0,0 @@
name: Feature Request
description: 'Suggest an idea for Sonarr'
labels: ['needs-triage']
body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an open or closed issue already exists for the feature you are requesting. If a feature request exists and it is closed as complete it may not yet be in a stable release.
options:
- label: I have searched the existing open and closed issues
required: true
- type: textarea
attributes:
label: Is your feature request related to a problem? Please describe
description: A clear and concise description of what the problem is.
validations:
required: true
- type: textarea
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
attributes:
label: Describe alternatives you've considered
description: A clear and concise description of any alternative solutions or features you've considered.
validations:
required: true
- type: textarea
attributes:
label: Anything else?
description: |
Links? References? Mockups? Anything that will give us more context about the feature you are encountering!
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: false

View File

@ -0,0 +1,7 @@
---
name: Other issues
about: How to get support or ask questions
---
Please use https://forums.sonarr.tv/ for support. Support requests or questions will be redirected to the forums and the issue will be closed.

View File

@ -1,15 +1,14 @@
#### Database Migration
YES | NO
#### Description
A few sentences describing the overall goals of the pull request's commits.
<!-- Remove any of the following sections if they are not used -->
#### Screenshots for UI Changes
#### Database Migration
YES - ###
#### Todos
- [ ] Tests
- [ ] Documentation
#### Issues Fixed or Closed by this PR
* Closes #
*

7
.github/SUPPORT.md vendored Normal file
View File

@ -0,0 +1,7 @@
## Support
There are a number of frequently asked questions that have been answered in our [FAQ](https://github.com/Sonarr/Sonarr/wiki/FAQ)
The [wiki](https://github.com/Sonarr/Sonarr/wiki) contains other information and guides
If you have a support question, please use the [support forums](https://forums.sonarr.tv/).

View File

@ -1,29 +0,0 @@
name: Archive
description: Archive binaries for deployment
inputs:
os:
description: 'OS that the packaging is running on'
required: true
artifact:
description: 'Binary artifact'
required: true
archive_type:
description: 'File type to use for the final package'
required: true
branch:
description: 'Git branch used for this build'
required: true
major_version:
description: 'Sonarr major version'
required: true
version:
description: 'Sonarr version'
required: true
runs:
using: 'composite'
steps:
- name: Archive Artifact
uses: thedoctor0/zip-release@0.7.5

View File

@ -1,78 +0,0 @@
name: Package
description: Packages binaries for deployment
inputs:
platform:
description: 'Binary platform'
required: true
framework:
description: '.net framework'
required: true
artifact:
description: 'Binary artifact'
required: true
branch:
description: 'Git branch used for this build'
required: true
major_version:
description: 'Sonarr major version'
required: true
version:
description: 'Sonarr version'
required: true
runs:
using: 'composite'
steps:
- name: Download Artifact
uses: actions/download-artifact@v4
with:
name: ${{ inputs.artifact }}
path: _output
- name: Download UI Artifact
uses: actions/download-artifact@v4
with:
name: build_ui
path: _output/UI
- name: Configure Environment Variables
shell: bash
run: |
echo "FRAMEWORK=${{ inputs.framework }}" >> "$GITHUB_ENV"
echo "BRANCH=${{ inputs.branch }}" >> "$GITHUB_ENV"
echo "SONARR_MAJOR_VERSION=${{ inputs.major_version }}" >> "$GITHUB_ENV"
echo "SONARR_VERSION=${{ inputs.version }}" >> "$GITHUB_ENV"
- name: Create Packages
shell: bash
run: $GITHUB_ACTION_PATH/package.sh
- name: Create Windows Installer (x64)
if: ${{ inputs.platform == 'windows' }}
working-directory: distribution/windows/setup
shell: cmd
run: |
SET RUNTIME=win-x64
build.bat
- name: Create Windows Installer (x86)
if: ${{ inputs.platform == 'windows' }}
working-directory: distribution/windows/setup
shell: cmd
run: |
SET RUNTIME=win-x86
build.bat
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: release_${{ inputs.platform }}
compression-level: 0
if-no-files-found: error
path: |
_artifacts/*.exe
_artifacts/*.tar.gz
_artifacts/*.zip

View File

@ -1,67 +0,0 @@
#!/bin/bash
outputFolder=_output
artifactsFolder=_artifacts
uiFolder="$outputFolder/UI"
framework="${FRAMEWORK:=net6.0}"
rm -rf $artifactsFolder
mkdir $artifactsFolder
for runtime in _output/*
do
name="${runtime##*/}"
folderName="$runtime/$framework"
sonarrFolder="$folderName/Sonarr"
archiveName="Sonarr.$BRANCH.$SONARR_VERSION.$name"
if [[ "$name" == 'UI' ]]; then
continue
fi
echo "Creating package for $name"
echo "Copying UI"
cp -r $uiFolder $sonarrFolder
echo "Setting permissions"
find $sonarrFolder -name "ffprobe" -exec chmod a+x {} \;
find $sonarrFolder -name "Sonarr" -exec chmod a+x {} \;
find $sonarrFolder -name "Sonarr.Update" -exec chmod a+x {} \;
if [[ "$name" == *"osx"* ]]; then
echo "Creating macOS package"
packageName="$name-app"
packageFolder="$outputFolder/$packageName"
rm -rf $packageFolder
mkdir $packageFolder
cp -r distribution/macOS/Sonarr.app $packageFolder
mkdir -p $packageFolder/Sonarr.app/Contents/MacOS
echo "Copying Binaries"
cp -r $sonarrFolder/* $packageFolder/Sonarr.app/Contents/MacOS
echo "Removing Update Folder"
rm -r $packageFolder/Sonarr.app/Contents/MacOS/Sonarr.Update
echo "Packaging macOS app Artifact"
(cd $packageFolder; zip -rq "../../$artifactsFolder/$archiveName-app.zip" ./Sonarr.app)
fi
echo "Packaging Artifact"
if [[ "$name" == *"linux"* ]] || [[ "$name" == *"osx"* ]] || [[ "$name" == *"freebsd"* ]]; then
tar -zcf "./$artifactsFolder/$archiveName.tar.gz" -C $folderName Sonarr
fi
if [[ "$name" == *"win"* ]]; then
if [ "$RUNNER_OS" = "Windows" ]
then
(cd $folderName; 7z a -tzip "../../../$artifactsFolder/$archiveName.zip" ./Sonarr)
else
(cd $folderName; zip -rq "../../../$artifactsFolder/$archiveName.zip" ./Sonarr)
fi
fi
done

View File

@ -1,18 +0,0 @@
name: Publish Test Artifact
description: Publishes a test artifact
inputs:
framework:
description: '.net framework'
required: true
runtime:
description: '.net runtime'
required: true
runs:
using: 'composite'
steps:
- uses: actions/upload-artifact@v4
with:
name: tests-${{ inputs.runtime }}
path: _tests/${{ inputs.framework }}/${{ inputs.runtime }}/publish/**/*

View File

@ -1,87 +0,0 @@
name: Test
description: Runs unit/integration tests
inputs:
use_postgres:
description: 'Whether postgres should be used for the database'
os:
description: 'OS that the tests are running on'
required: true
artifact:
description: 'Test binary artifact'
required: true
pattern:
description: 'Pattern for DLLs'
required: true
filter:
description: 'Filter for tests'
required: true
integration_tests:
description: 'True if running integration tests'
binary_artifact:
description: 'Binary artifact for integration tests'
binary_path:
description: 'Path witin binary artifact for integration tests'
runs:
using: 'composite'
steps:
- name: Setup .NET
uses: actions/setup-dotnet@v4
- name: Setup Postgres
if: ${{ inputs.use_postgres }}
uses: ikalnytskyi/action-setup-postgres@v4
- name: Setup Test Variables
shell: bash
run: |
echo "RESULTS_NAME=${{ inputs.integration_tests && 'integation-' || 'unit-' }}${{ inputs.artifact }}${{ inputs.use_postgres && '-postgres' }}" >> "$GITHUB_ENV"
- name: Setup Postgres Environment Variables
if: ${{ inputs.use_postgres }}
shell: bash
run: |
echo "Sonarr__Postgres__Host=localhost" >> "$GITHUB_ENV"
echo "Sonarr__Postgres__Port=5432" >> "$GITHUB_ENV"
echo "Sonarr__Postgres__User=postgres" >> "$GITHUB_ENV"
echo "Sonarr__Postgres__Password=postgres" >> "$GITHUB_ENV"
- name: Download Artifact
uses: actions/download-artifact@v4
with:
name: ${{ inputs.artifact }}
path: _tests
- name: Download Binary Artifact
if: ${{ inputs.integration_tests }}
uses: actions/download-artifact@v4
with:
name: ${{ inputs.binary_artifact }}
path: _output
- name: Set up binary artifact
if: ${{ inputs.binary_path != '' }}
shell: bash
run: mv ./_output/${{inputs.binary_path}} _tests/bin
- name: Make executable
if: startsWith(inputs.os, 'windows') != true
shell: bash
run: chmod +x ./_tests/Sonarr.Test.Dummy && chmod +x ./_tests/ffprobe
- name: Make Sonarr binary executable
if: ${{ inputs.integration_tests && !startsWith(inputs.os, 'windows') }}
shell: bash
run: chmod +x ./_tests/bin/Sonarr
- name: Run tests
shell: bash
run: dotnet test ./_tests/Sonarr.*.Test.dll --filter "${{ inputs.filter }}" --logger "trx;LogFileName=${{ env.RESULTS_NAME }}.trx" --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
- name: Upload Test Results
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: results-${{ env.RESULTS_NAME }}
path: TestResults/*.trx

View File

@ -1,12 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for more information:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
# https://containers.dev/guide/dependabot
version: 2
updates:
- package-ecosystem: "devcontainers"
directory: "/"
schedule:
interval: weekly

23
.github/labeler.yml vendored
View File

@ -1,23 +0,0 @@
'connection':
- changed-files:
- any-glob-to-any-file: src/NzbDrone.Core/Notifications/**/*
'db-migration':
- changed-files:
- any-glob-to-any-file: src/NzbDrone.Core/Datastore/Migration/*
'download-client':
- changed-files:
- any-glob-to-any-file: src/NzbDrone.Core/Download/Clients/**/*
'indexer':
- changed-files:
- any-glob-to-any-file: src/NzbDrone.Core/Indexers/**/*
'parsing':
- changed-files:
- any-glob-to-any-file: src/NzbDrone.Core/Parser/**/*
'ui-only':
- changed-files:
- any-glob-to-all-files: frontend/**/*

9
.github/release.yml vendored
View File

@ -1,9 +0,0 @@
changelog:
exclude:
authors:
- Weblate
- SonarrBot
categories:
- title: Changes
labels:
- '*'

View File

@ -1,52 +0,0 @@
name: 'API Docs'
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * 1'
push:
branches:
- develop
paths:
- ".github/workflows/api_docs.yml"
- "docs.sh"
- "src/Sonarr.Api.*/**"
- "src/Sonarr.Http/**"
- "src/**/*.csproj"
- "src/*"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
api_docs:
runs-on: ubuntu-latest
if: github.repository == 'Sonarr/Sonarr'
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Setup dotnet
uses: actions/setup-dotnet@v4
id: setup-dotnet
- name: Create openapi.json
run: ./docs.sh Linux
- name: Commit API Docs Change
continue-on-error: true
run: |
git config --global user.email "development@sonarr.tv"
git config --global user.name "Sonarr"
git checkout -b api-docs
git add src
if git status | grep -q modified
then
git commit -am 'Automated API Docs update' -m "ignore-downstream"
git push -f --set-upstream origin api-docs
curl -X POST -H "Authorization: Bearer ${{ secrets.OPENAPI_PAT }}" -H "Accept: application/vnd.github+json" https://api.github.com/repos/sonarr/sonarr/pulls -d '{"head":"api-docs","base":"develop","title":"Update API docs"}'
else
echo "No changes since last run"
fi

View File

@ -1,257 +0,0 @@
name: Build
on:
push:
branches:
- develop
- main
paths-ignore:
- "src/Sonarr.Api.*/openapi.json"
pull_request:
branches:
- develop
paths-ignore:
- "src/NzbDrone.Core/Localization/Core/**"
- "src/Sonarr.Api.*/openapi.json"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
FRAMEWORK: net6.0
RAW_BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
SONARR_MAJOR_VERSION: 4
VERSION: 4.0.8
jobs:
backend:
runs-on: windows-latest
outputs:
framework: ${{ steps.variables.outputs.framework }}
major_version: ${{ steps.variables.outputs.major_version }}
version: ${{ steps.variables.outputs.version }}
steps:
- name: Check out
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
- name: Setup Environment Variables
id: variables
shell: bash
run: |
# Add 800 to the build number because GitHub won't let us pick an arbitrary starting point
SONARR_VERSION="${{ env.VERSION }}.$((${{ github.run_number }}+800))"
DOTNET_VERSION=$(jq -r '.sdk.version' global.json)
echo "SDK_PATH=${{ env.DOTNET_ROOT }}/sdk/${DOTNET_VERSION}" >> "$GITHUB_ENV"
echo "SONARR_VERSION=$SONARR_VERSION" >> "$GITHUB_ENV"
echo "BRANCH=${RAW_BRANCH_NAME//\//-}" >> "$GITHUB_ENV"
echo "framework=${{ env.FRAMEWORK }}" >> "$GITHUB_OUTPUT"
echo "major_version=${{ env.SONARR_MAJOR_VERSION }}" >> "$GITHUB_OUTPUT"
echo "version=$SONARR_VERSION" >> "$GITHUB_OUTPUT"
- name: Enable Extra Platforms In SDK
shell: bash
run: ./build.sh --enable-extra-platforms-in-sdk
- name: Build Backend
shell: bash
run: ./build.sh --backend --enable-extra-platforms --packages
# Test Artifacts
- name: Publish win-x64 Test Artifact
uses: ./.github/actions/publish-test-artifact
with:
framework: ${{ env.FRAMEWORK }}
runtime: win-x64
- name: Publish linux-x64 Test Artifact
uses: ./.github/actions/publish-test-artifact
with:
framework: ${{ env.FRAMEWORK }}
runtime: linux-x64
- name: Publish osx-arm64 Test Artifact
uses: ./.github/actions/publish-test-artifact
with:
framework: ${{ env.FRAMEWORK }}
runtime: osx-arm64
# Build Artifacts (grouped by OS)
- name: Publish FreeBSD Artifact
uses: actions/upload-artifact@v4
with:
name: build_freebsd
path: _artifacts/freebsd-*/**/*
- name: Publish Linux Artifact
uses: actions/upload-artifact@v4
with:
name: build_linux
path: _artifacts/linux-*/**/*
- name: Publish macOS Artifact
uses: actions/upload-artifact@v4
with:
name: build_macos
path: _artifacts/osx-*/**/*
- name: Publish Windows Artifact
uses: actions/upload-artifact@v4
with:
name: build_windows
path: _artifacts/win-*/**/*
frontend:
runs-on: ubuntu-latest
steps:
- name: Check out
uses: actions/checkout@v4
- name: Volta
uses: volta-cli/action@v4
- name: Yarn Install
run: yarn install
- name: Lint
run: yarn lint
- name: Stylelint
run: yarn stylelint -f github
- name: Build
run: yarn build --env production
- name: Publish UI Artifact
uses: actions/upload-artifact@v4
with:
name: build_ui
path: _output/UI/**/*
unit_test:
needs: backend
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
include:
- os: ubuntu-latest
artifact: tests-linux-x64
filter: TestCategory!=ManualTest&TestCategory!=WINDOWS&TestCategory!=IntegrationTest&TestCategory!=AutomationTest
- os: macos-latest
artifact: tests-osx-arm64
filter: TestCategory!=ManualTest&TestCategory!=WINDOWS&TestCategory!=IntegrationTest&TestCategory!=AutomationTest
- os: windows-latest
artifact: tests-win-x64
filter: TestCategory!=ManualTest&TestCategory!=LINUX&TestCategory!=IntegrationTest&TestCategory!=AutomationTest
runs-on: ${{ matrix.os }}
steps:
- name: Check out
uses: actions/checkout@v4
- name: Test
uses: ./.github/actions/test
with:
os: ${{ matrix.os }}
artifact: ${{ matrix.artifact }}
pattern: Sonarr.*.Test.dll
filter: ${{ matrix.filter }}
unit_test_postgres:
needs: backend
runs-on: ubuntu-latest
steps:
- name: Check out
uses: actions/checkout@v4
- name: Test
uses: ./.github/actions/test
with:
os: ubuntu-latest
artifact: tests-linux-x64
pattern: Sonarr.*.Test.dll
filter: TestCategory!=ManualTest&TestCategory!=WINDOWS&TestCategory!=IntegrationTest&TestCategory!=AutomationTest
use_postgres: true
integration_test:
needs: backend
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
include:
- os: ubuntu-latest
artifact: tests-linux-x64
filter: TestCategory!=ManualTest&TestCategory!=WINDOWS&TestCategory=IntegrationTest
binary_artifact: build_linux
binary_path: linux-x64/${{ needs.backend.outputs.framework }}/Sonarr
- os: macos-latest
artifact: tests-osx-arm64
filter: TestCategory!=ManualTest&TestCategory!=WINDOWS&TestCategory=IntegrationTest
binary_artifact: build_macos
binary_path: osx-arm64/${{ needs.backend.outputs.framework }}/Sonarr
- os: windows-latest
artifact: tests-win-x64
filter: TestCategory!=ManualTest&TestCategory!=LINUX&TestCategory=IntegrationTest
binary_artifact: build_windows
binary_path: win-x64/${{ needs.backend.outputs.framework }}/Sonarr
runs-on: ${{ matrix.os }}
steps:
- name: Check out
uses: actions/checkout@v4
- name: Test
uses: ./.github/actions/test
with:
os: ${{ matrix.os }}
artifact: ${{ matrix.artifact }}
pattern: Sonarr.*.Test.dll
filter: ${{ matrix.filter }}
integration_tests: true
binary_artifact: ${{ matrix.binary_artifact }}
binary_path: ${{ matrix.binary_path }}
deploy:
if: ${{ github.ref_name == 'develop' || github.ref_name == 'main' }}
needs: [backend, frontend, unit_test, unit_test_postgres, integration_test]
secrets: inherit
uses: ./.github/workflows/deploy.yml
with:
framework: ${{ needs.backend.outputs.framework }}
branch: ${{ github.ref_name }}
major_version: ${{ needs.backend.outputs.major_version }}
version: ${{ needs.backend.outputs.version }}
notify:
name: Discord Notification
needs:
[
backend,
frontend,
unit_test,
unit_test_postgres,
integration_test,
deploy,
]
if: ${{ !cancelled() && (github.ref_name == 'develop' || github.ref_name == 'main') }}
env:
STATUS: ${{ contains(needs.*.result, 'failure') && 'failure' || 'success' }}
runs-on: ubuntu-latest
steps:
- name: Notify
uses: tsickert/discord-webhook@v6.0.0
with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
username: "GitHub Actions"
avatar-url: "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"
embed-title: "${{ github.workflow }}: ${{ env.STATUS == 'success' && 'Success' || 'Failure' }}"
embed-url: "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
embed-description: |
**Branch** ${{ github.ref }}
**Build** ${{ needs.backend.outputs.version }}
embed-color: ${{ env.STATUS == 'success' && '3066993' || '15158332' }}

View File

@ -1,26 +0,0 @@
name: Merge Conflict Labeler
on:
push:
branches:
- develop
pull_request_target:
branches:
- develop
types: [synchronize]
jobs:
label:
name: Labeling
runs-on: ubuntu-latest
if: ${{ github.repository == 'Sonarr/Sonarr' }}
permissions:
contents: read
pull-requests: write
steps:
- name: Apply label
uses: eps1lon/actions-label-merge-conflict@v3
with:
dirtyLabel: 'merge-conflict'
repoToken: '${{ secrets.GITHUB_TOKEN }}'

View File

@ -1,160 +0,0 @@
name: Deploy
on:
workflow_call:
inputs:
framework:
description: '.net framework'
type: string
required: true
branch:
description: 'Git branch used for this build'
type: string
required: true
major_version:
description: 'Sonarr major version'
type: string
required: true
version:
description: 'Sonarr version'
type: string
required: true
secrets:
SERVICES_API_KEY:
required: true
jobs:
package:
strategy:
matrix:
platform: [freebsd, linux, macos, windows]
include:
- platform: freebsd
os: ubuntu-latest
- platform: linux
os: ubuntu-latest
- platform: macos
os: ubuntu-latest
- platform: windows
os: windows-latest
runs-on: ${{ matrix.os }}
steps:
- name: Check out
uses: actions/checkout@v4
- name: Package
uses: ./.github/actions/package
with:
framework: ${{ inputs.framework }}
platform: ${{ matrix.platform }}
artifact: build_${{ matrix.platform }}
branch: ${{ inputs.branch }}
major_version: ${{ inputs.major_version }}
version: ${{ inputs.version }}
release:
needs: package
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Check out
uses: actions/checkout@v4
- name: Download release artifacts
uses: actions/download-artifact@v4
with:
path: _artifacts
pattern: release_*
merge-multiple: true
- name: Get Previous Release
id: previous-release
uses: cardinalby/git-get-release-action@v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
latest: true
prerelease: ${{ inputs.branch != 'main' }}
- name: Generate Release Notes
id: generate-release-notes
uses: actions/github-script@v7
with:
github-token: ${{ github.token }}
result-encoding: string
script: |
const { data } = await github.rest.repos.generateReleaseNotes({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: 'v${{ inputs.version }}',
target_commitish: '${{ github.sha }}',
previous_tag_name: '${{ steps.previous-release.outputs.tag_name }}',
})
return data.body
- name: Create release
uses: ncipollo/release-action@v1
with:
artifacts: _artifacts/Sonarr.*
commit: ${{ github.sha }}
generateReleaseNotes: false
body: ${{ steps.generate-release-notes.outputs.result }}
name: ${{ inputs.version }}
prerelease: ${{ inputs.branch != 'main' }}
skipIfReleaseExists: true
tag: v${{ inputs.version }}
- name: Publish to Services
shell: bash
working-directory: _artifacts
run: |
branch=${{ inputs.branch }}
version=${{ inputs.version }}
lastCommit=${{ github.sha }}
hashes="["
addHash() {
path=$1
os=$2
arch=$3
type=$4
local hash=$(sha256sum *.$version.$path | awk '{ print $1; }')
echo "{ \""Os\"": \""$os\"", \""Arch\"": \""$arch\"", \""Type\"": \""$type\"", \""Hash\"": \""$hash\"" }"
}
hashes="$hashes $(addHash "linux-arm.tar.gz" "linux" "arm" "archive")"
hashes="$hashes, $(addHash "linux-arm64.tar.gz" "linux" "arm64" "archive")"
hashes="$hashes, $(addHash "linux-x64.tar.gz" "linux" "x64" "archive")"
# hashes="$hashes, $(addHash "linux-x86.tar.gz" "linux" "x86" "archive")"
# hashes="$hashes, $(addHash "linux-musl-arm.tar.gz" "linuxmusl" "arm" "archive")"
hashes="$hashes, $(addHash "linux-musl-arm64.tar.gz" "linuxmusl" "arm64" "archive")"
hashes="$hashes, $(addHash "linux-musl-x64.tar.gz" "linuxmusl" "x64" "archive")"
hashes="$hashes, $(addHash "osx-arm64.tar.gz" "osx" "arm64" "archive")"
hashes="$hashes, $(addHash "osx-x64.tar.gz" "osx" "x64" "archive")"
hashes="$hashes, $(addHash "osx-arm64-app.zip" "osx" "arm64" "installer")"
hashes="$hashes, $(addHash "osx-x64-app.zip" "osx" "x64" "installer")"
hashes="$hashes, $(addHash "win-x64.zip" "windows" "x64" "archive")"
hashes="$hashes, $(addHash "win-x86.zip" "windows" "x86" "archive")"
hashes="$hashes, $(addHash "win-x64-installer.exe" "windows" "x64" "installer")"
hashes="$hashes, $(addHash "win-x86-installer.exe" "windows" "x86" "installer")"
hashes="$hashes, $(addHash "freebsd-x64.tar.gz" "freebsd" "x64" "archive")"
hashes="$hashes ]"
json="{\""branch\"":\""$branch\"", \""version\"":\""$version\"", \""lastCommit\"":\""$lastCommit\"", \""hashes\"":$hashes, \""gitHubRelease\"":true}"
url="https://services.sonarr.tv/v1/update"
echo "Publishing update $version ($branch) to: $url"
echo "$json"
curl -H "Content-Type: application/json" -H "X-Api-Key: ${{ secrets.SERVICES_API_KEY }}" -X POST -d "$json" --fail-with-body $url

View File

@ -1,13 +0,0 @@
name: "Pull Request Labeler"
on:
- pull_request_target
jobs:
triage:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
if: github.repository == 'Sonarr/Sonarr'
steps:
- uses: actions/labeler@v5

View File

@ -1,22 +0,0 @@
name: 'Lock threads'
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * *'
jobs:
lock:
runs-on: ubuntu-latest
if: github.repository == 'Sonarr/Sonarr'
steps:
- uses: dessant/lock-threads@v5
with:
github-token: ${{ github.token }}
issue-inactive-days: '90'
exclude-issue-created-before: ''
exclude-any-issue-labels: 'one-day-maybe'
add-issue-labels: ''
issue-comment: ''
issue-lock-reason: 'resolved'
process-only: ''

34
.gitignore vendored
View File

@ -45,10 +45,6 @@ _dotCover*
# DevExpress CodeRush
src/.cr/
# Emacs
*~
\#*\#
# NCrunch
*.ncrunch*
.*crunch*.local.xml
@ -84,6 +80,7 @@ TestResults
[Tt]est[Rr]esult*
*.Cache
ClientBin
[Ss]tyle[Cc]op.*
~$*
*.dbmdl
Generated_Code #added for RIA/Silverlight projects
@ -116,36 +113,20 @@ src/UI/.idea/*
*log.txt
node_modules/
_output*
_artifacts
_rawPackage/
_dotTrace*
_tests*
_publish*
_temp*
_tests/
*.Result.xml
coverage*.xml
coverage*.json
setup/Output/
*.~is
.mono
UI/
#VS outout folders
bin
obj
output/*
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
# Packages
Sonarr_*/
Sonarr_*.zip
Sonarr_*.gz
gecko.zip
geckodriver.exe
#OS X metadata files
._*
@ -154,11 +135,4 @@ geckodriver.exe
_start
_temp_*/**/*
# Windows thumbnail cache files
Thumbs.db
src/.idea/
/distribution/windows/setup/output/*
# API doc generation
.config/

4
.gitmodules vendored Normal file
View File

@ -0,0 +1,4 @@
[submodule "src/ExternalModules/CurlSharp"]
path = src/ExternalModules/CurlSharp
url = https://github.com/Sonarr/CurlSharp.git
branch = master

1
.npmrc Normal file
View File

@ -0,0 +1 @@
save-prefix=""

View File

@ -1,7 +0,0 @@
{
"recommendations": [
"esbenp.prettier-vscode",
"ms-dotnettools.csdevkit",
"ms-vscode-remote.remote-containers"
]
}

26
.vscode/launch.json vendored
View File

@ -1,26 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md
"name": "Run Sonarr",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build dotnet",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/_output/net6.0/Sonarr",
"args": [],
"cwd": "${workspaceFolder}",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "integratedTerminal",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}

View File

@ -1,3 +0,0 @@
{
"typescript.tsdk": "node_modules\\typescript\\lib"
}

44
.vscode/tasks.json vendored
View File

@ -1,44 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build dotnet",
"command": "dotnet",
"type": "process",
"args": [
"msbuild",
"-restore",
"${workspaceFolder}/src/Sonarr.sln",
"-p:GenerateFullPaths=true",
"-p:Configuration=Debug",
"-p:Platform=Posix",
"-consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/src/Sonarr.sln",
"-property:GenerateFullPaths=true",
"-consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/src/Sonarr.sln"
],
"problemMatcher": "$msCompile"
}
]
}

View File

@ -1,2 +1 @@
save-exact true
registry "https://registry.yarnpkg.com"
save-prefix ""

View File

@ -3,40 +3,39 @@
We're always looking for people to help make Sonarr even better, there are a number of ways to contribute.
## Documentation ##
Setup guides, [FAQ](https://wiki.servarr.com/sonarr/faq), the more information we have on the [wiki](https://wiki.servarr.com/sonarr) the better.
Setup guides, FAQ, the more information we have on the wiki the better.
## Development ##
### Tools required ###
- Visual Studio 2019 or higher (https://www.visualstudio.com/vs/). The community version is free and works (https://www.visualstudio.com/downloads/).
- HTML/Javascript editor of choice (VS Code/Sublime Text/Webstorm/Atom/etc)
- [Git](https://git-scm.com/downloads)
- [NodeJS](https://nodejs.org/en/download/) (Node 10.X.X or higher)
- [Yarn](https://yarnpkg.com/)
- Visual Studio 2015
- HTML/Javascript editor of choice (Sublime Text/Webstorm/Atom/etc)
- npm (node package manager)
- git
### Getting started ###
1. Fork Sonarr
2. Clone the repository into your development machine. [*info*](https://docs.github.com/en/get-started/quickstart/fork-a-repo)
3. Install the required Node Packages `yarn install`
4. Start webpack to monitor your dev environment for any frontend changes that need post processing using `yarn start` command.
5. Build the project in Visual Studio, Setting startup project to `Sonarr.Console` and framework to `x86`
6. Debug the project in Visual Studio
7. Open http://localhost:8989
1. Fork Sonarr
2. Clone (develop branch) *you may need pull in submodules separately if you client doesn't clone them automatically (CurlSharp)*
3. Run `npm install`
4. Run `npm start` - Used to compile the UI components and copy them.
Leave this window open.
If you have gulp globally installed you can use `gulp watch` instead
5. Compile in Visual Studio
### Contributing Code ###
- If you're adding a new, already requested feature, please comment on [Github Issues](https://github.com/Sonarr/Sonarr/issues "Github Issues") so work is not duplicated (If you want to add something not already on there, please talk to us first)
- Rebase from Sonarr's `develop` branch, don't merge
- Rebase from Sonarr's develop branch, don't merge
- Make meaningful commits, or squash them
- Feel free to make a pull request before work is complete, this will let us see where its at and make comments/suggest improvements
- Reach out to us on our [forums](https://forums.sonarr.tv/), [subreddit](https://www.reddit.com/r/sonarr/), [discord](https://discord.gg/Ex7FmFK), or [IRC](https://web.libera.chat/?channels=#sonarr) if you have any questions
- Reach out to us on the forums or on IRC if you have any questions
- Add tests (unit/integration)
- Commit with *nix line endings for consistency (We checkout Windows and commit *nix)
- One feature/bug fix per pull request to keep things clean and easy to understand
- Use 4 spaces instead of tabs, this should be the default for VS 2019 and WebStorm
- Use 4 spaces instead of tabs, this is the default for VS 2012 and WebStorm (to my knowledge)
### Pull Requesting ###
- Only make pull requests to develop (currently `develop`), never `main`, if you make a PR to master we'll comment on it and close it
- Only make pull requests to develop, never master, if you make a PR to master we'll comment on it and close it
- You're probably going to get some comments or questions from us, they will be to ensure consistency and maintainability
- We'll try to respond to pull requests as soon as possible, if its been a day or two, please reach out to us, we may have missed it
- Each PR should come from its own [feature branch](http://martinfowler.com/bliki/FeatureBranch.html) not develop in your fork, it should have a meaningful branch name (what is being added/fixed)

View File

@ -1,12 +0,0 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: sonarr
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="70px" height="70px" viewBox="0 0 70 70" style="enable-background:new 0 0 70 70;" xml:space="preserve">
<g>
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-1.3318" y1="43.7371" x2="67.0419" y2="26.0967">
<stop offset="0.1237" style="stop-color:#7866FF"/>
<stop offset="0.5376" style="stop-color:#FE2EB6"/>
<stop offset="0.8548" style="stop-color:#FD0486"/>
</linearGradient>
<polygon style="fill:url(#SVGID_1_);" points="67.3,16 43.7,0 0,31.1 11.1,70 58.9,60.3 "/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="45.9148" y1="38.9098" x2="67.6577" y2="9.0989">
<stop offset="0.1237" style="stop-color:#FF0080"/>
<stop offset="0.2587" style="stop-color:#FE0385"/>
<stop offset="0.4109" style="stop-color:#FA0C92"/>
<stop offset="0.5713" style="stop-color:#F41BA9"/>
<stop offset="0.7363" style="stop-color:#EB2FC8"/>
<stop offset="0.8656" style="stop-color:#E343E6"/>
</linearGradient>
<polygon style="fill:url(#SVGID_2_);" points="67.3,16 43.7,0 38,15.7 38,47.8 70,47.8 "/>
</g>
<g>
<rect x="13.4" y="13.4" style="fill:#000000;" width="43.2" height="43.2"/>
<rect x="17.4" y="48.5" style="fill:#FFFFFF;" width="16.2" height="2.7"/>
<g>
<path style="fill:#FFFFFF;" d="M17.4,19.1h6.9c5.6,0,9.5,3.8,9.5,8.9V28c0,5-3.9,8.9-9.5,8.9h-6.9V19.1z M21.4,22.7v10.7h3
c3.2,0,5.4-2.2,5.4-5.3V28c0-3.2-2.2-5.4-5.4-5.4H21.4z"/>
<polygon style="fill:#FFFFFF;" points="40.3,22.7 34.9,22.7 34.9,19.1 49.6,19.1 49.6,22.7 44.2,22.7 44.2,37 40.3,37 "/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,66 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="120.1px" height="130.2px" viewBox="0 0 120.1 130.2" style="enable-background:new 0 0 120.1 130.2;" xml:space="preserve"
>
<g>
<linearGradient id="XMLID_2_" gradientUnits="userSpaceOnUse" x1="31.8412" y1="120.5578" x2="110.2402" y2="73.24">
<stop offset="0" style="stop-color:#FCEE39"/>
<stop offset="1" style="stop-color:#F37B3D"/>
</linearGradient>
<path id="XMLID_3041_" style="fill:url(#XMLID_2_);" d="M118.6,71.8c0.9-0.8,1.4-1.9,1.5-3.2c0.1-2.6-1.8-4.7-4.4-4.9
c-1.2-0.1-2.4,0.4-3.3,1.1l0,0l-83.8,45.9c-1.9,0.8-3.6,2.2-4.7,4.1c-2.9,4.8-1.3,11,3.6,13.9c3.4,2,7.5,1.8,10.7-0.2l0,0l0,0
c0.2-0.2,0.5-0.3,0.7-0.5l78-54.8C117.3,72.9,118.4,72.1,118.6,71.8L118.6,71.8L118.6,71.8z"/>
<linearGradient id="XMLID_3_" gradientUnits="userSpaceOnUse" x1="48.3607" y1="6.9083" x2="119.9179" y2="69.5546">
<stop offset="0" style="stop-color:#EF5A6B"/>
<stop offset="0.57" style="stop-color:#F26F4E"/>
<stop offset="1" style="stop-color:#F37B3D"/>
</linearGradient>
<path id="XMLID_3049_" style="fill:url(#XMLID_3_);" d="M118.8,65.1L118.8,65.1L55,2.5C53.6,1,51.6,0,49.3,0
c-4.3,0-7.7,3.5-7.7,7.7v0c0,2.1,0.8,3.9,2.1,5.3l0,0l0,0c0.4,0.4,0.8,0.7,1.2,1l67.4,57.7l0,0c0.8,0.7,1.8,1.2,3,1.3
c2.6,0.1,4.7-1.8,4.9-4.4C120.2,67.3,119.7,66,118.8,65.1z"/>
<linearGradient id="XMLID_4_" gradientUnits="userSpaceOnUse" x1="52.9467" y1="63.6407" x2="10.5379" y2="37.1562">
<stop offset="0" style="stop-color:#7C59A4"/>
<stop offset="0.3852" style="stop-color:#AF4C92"/>
<stop offset="0.7654" style="stop-color:#DC4183"/>
<stop offset="0.957" style="stop-color:#ED3D7D"/>
</linearGradient>
<path id="XMLID_3042_" style="fill:url(#XMLID_4_);" d="M57.1,59.5C57,59.5,17.7,28.5,16.9,28l0,0l0,0c-0.6-0.3-1.2-0.6-1.8-0.9
c-5.8-2.2-12.2,0.8-14.4,6.6c-1.9,5.1,0.2,10.7,4.6,13.4l0,0l0,0C6,47.5,6.6,47.8,7.3,48c0.4,0.2,45.4,18.8,45.4,18.8l0,0
c1.8,0.8,3.9,0.3,5.1-1.2C59.3,63.7,59,61,57.1,59.5z"/>
<linearGradient id="XMLID_5_" gradientUnits="userSpaceOnUse" x1="52.1736" y1="3.7019" x2="10.7706" y2="37.8971">
<stop offset="0" style="stop-color:#EF5A6B"/>
<stop offset="0.364" style="stop-color:#EE4E72"/>
<stop offset="1" style="stop-color:#ED3D7D"/>
</linearGradient>
<path id="XMLID_3057_" style="fill:url(#XMLID_5_);" d="M49.3,0c-1.7,0-3.3,0.6-4.6,1.5L4.9,28.3c-0.1,0.1-0.2,0.1-0.2,0.2l-0.1,0
l0,0c-1.7,1.2-3.1,3-3.9,5.1C-1.5,39.4,1.5,45.9,7.3,48c3.6,1.4,7.5,0.7,10.4-1.4l0,0l0,0c0.7-0.5,1.3-1,1.8-1.6l34.6-31.2l0,0
c1.8-1.4,3-3.6,3-6.1v0C57.1,3.5,53.6,0,49.3,0z"/>
<g id="XMLID_3008_">
<rect id="XMLID_3033_" x="34.6" y="37.4" style="fill:#000000;" width="51" height="51"/>
<rect id="XMLID_3032_" x="39" y="78.8" style="fill:#FFFFFF;" width="19.1" height="3.2"/>
<g id="XMLID_3009_">
<path id="XMLID_3030_" style="fill:#FFFFFF;" d="M38.8,50.8l1.5-1.4c0.4,0.5,0.8,0.8,1.3,0.8c0.6,0,0.9-0.4,0.9-1.2l0-5.3l2.3,0
l0,5.3c0,1-0.3,1.8-0.8,2.3c-0.5,0.5-1.3,0.8-2.3,0.8C40.2,52.2,39.4,51.6,38.8,50.8z"/>
<path id="XMLID_3028_" style="fill:#FFFFFF;" d="M45.3,43.8l6.7,0v1.9l-4.4,0V47l4,0l0,1.8l-4,0l0,1.3l4.5,0l0,2l-6.7,0
L45.3,43.8z"/>
<path id="XMLID_3026_" style="fill:#FFFFFF;" d="M55,45.8l-2.5,0l0-2l7.3,0l0,2l-2.5,0l0,6.3l-2.3,0L55,45.8z"/>
<path id="XMLID_3022_" style="fill:#FFFFFF;" d="M39,54l4.3,0c1,0,1.8,0.3,2.3,0.7c0.3,0.3,0.5,0.8,0.5,1.4v0
c0,1-0.5,1.5-1.3,1.9c1,0.3,1.6,0.9,1.6,2v0c0,1.4-1.2,2.3-3.1,2.3l-4.3,0L39,54z M43.8,56.6c0-0.5-0.4-0.7-1-0.7l-1.5,0l0,1.5
l1.4,0C43.4,57.3,43.8,57.1,43.8,56.6L43.8,56.6z M43,59l-1.8,0l0,1.5H43c0.7,0,1.1-0.3,1.1-0.8v0C44.1,59.2,43.7,59,43,59z"/>
<path id="XMLID_3019_" style="fill:#FFFFFF;" d="M46.8,54l3.9,0c1.3,0,2.1,0.3,2.7,0.9c0.5,0.5,0.7,1.1,0.7,1.9v0
c0,1.3-0.7,2.1-1.7,2.6l2,2.9l-2.6,0l-1.7-2.5h-1l0,2.5l-2.3,0L46.8,54z M50.6,58c0.8,0,1.2-0.4,1.2-1v0c0-0.7-0.5-1-1.2-1
l-1.5,0v2H50.6z"/>
<path id="XMLID_3016_" style="fill:#FFFFFF;" d="M56.8,54l2.2,0l3.5,8.4l-2.5,0l-0.6-1.5l-3.2,0l-0.6,1.5l-2.4,0L56.8,54z
M58.8,59l-0.9-2.3L57,59L58.8,59z"/>
<path id="XMLID_3014_" style="fill:#FFFFFF;" d="M62.8,54l2.3,0l0,8.3l-2.3,0L62.8,54z"/>
<path id="XMLID_3012_" style="fill:#FFFFFF;" d="M65.7,54l2.1,0l3.4,4.4l0-4.4l2.3,0l0,8.3l-2,0L68,57.8l0,4.6l-2.3,0L65.7,54z"
/>
<path id="XMLID_3010_" style="fill:#FFFFFF;" d="M73.7,61.1l1.3-1.5c0.8,0.7,1.7,1,2.7,1c0.6,0,1-0.2,1-0.6v0
c0-0.4-0.3-0.5-1.4-0.8c-1.8-0.4-3.1-0.9-3.1-2.6v0c0-1.5,1.2-2.7,3.2-2.7c1.4,0,2.5,0.4,3.4,1.1l-1.2,1.6
c-0.8-0.5-1.6-0.8-2.3-0.8c-0.6,0-0.8,0.2-0.8,0.5v0c0,0.4,0.3,0.5,1.4,0.8c1.9,0.4,3.1,1,3.1,2.6v0c0,1.7-1.3,2.7-3.4,2.7
C76.1,62.5,74.7,62,73.7,61.1z"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -1,50 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="70px" height="70px" viewBox="0 0 70 70" style="enable-background:new 0 0 70 70;" xml:space="preserve">
<g>
<g>
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="22.9451" y1="75.7869" x2="74.7868" y2="20.6415">
<stop offset="1.612903e-002" style="stop-color:#B35BA3"/>
<stop offset="0.4044" style="stop-color:#C41E57"/>
<stop offset="0.4677" style="stop-color:#C41E57"/>
<stop offset="0.6505" style="stop-color:#EB8523"/>
<stop offset="0.9516" style="stop-color:#FEBD11"/>
</linearGradient>
<polygon style="fill:url(#SVGID_1_);" points="49.8,15.2 36,36.7 58.4,70 70,23.1 "/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="17.7187" y1="73.2922" x2="69.5556" y2="18.1519">
<stop offset="1.612903e-002" style="stop-color:#B35BA3"/>
<stop offset="0.4044" style="stop-color:#C41E57"/>
<stop offset="0.4677" style="stop-color:#C41E57"/>
<stop offset="0.7043" style="stop-color:#EB8523"/>
</linearGradient>
<polygon style="fill:url(#SVGID_2_);" points="51.1,15.7 49,0 18.8,33.6 27.6,42.3 20.8,70 58.4,70 "/>
</g>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="1.8281" y1="53.4275" x2="48.8245" y2="9.2255">
<stop offset="1.612903e-002" style="stop-color:#B35BA3"/>
<stop offset="0.6613" style="stop-color:#C41E57"/>
</linearGradient>
<polygon style="fill:url(#SVGID_3_);" points="49,0 11.6,0 0,47.1 55.6,47.1 "/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="49.8935" y1="-11.5569" x2="48.8588" y2="24.0352">
<stop offset="0.5" style="stop-color:#C41E57"/>
<stop offset="0.6668" style="stop-color:#D13F48"/>
<stop offset="0.7952" style="stop-color:#D94F39"/>
<stop offset="0.8656" style="stop-color:#DD5433"/>
</linearGradient>
<polygon style="fill:url(#SVGID_4_);" points="55.3,47.1 51.1,15.7 49,0 41.7,23 "/>
</g>
<g>
<rect x="13.4" y="13.5" transform="matrix(-1 2.577289e-003 -2.577289e-003 -1 70.0288 70.081)" style="fill:#000000;" width="43.2" height="43.2"/>
<rect x="17.6" y="48.6" transform="matrix(1 -2.577289e-003 2.577289e-003 1 -0.1287 6.634109e-002)" style="fill:#FFFFFF;" width="16.2" height="2.7"/>
<path style="fill:#FFFFFF;" d="M17.4,19.1l8.2,0c2.3,0,4,0.6,5.2,1.8c1,1,1.5,2.4,1.5,4.1l0,0.1c0,1.5-0.3,2.6-1.1,3.5
c-0.7,0.9-1.6,1.6-2.8,2l4.4,6.4l-4.6,0l-3.7-5.5l-3.3,0l0,5.5l-3.9,0L17.4,19.1z M25.3,27.8c1,0,1.7-0.2,2.2-0.7
c0.5-0.5,0.8-1.1,0.8-1.8l0-0.1c0-0.9-0.3-1.5-0.8-1.9c-0.5-0.4-1.3-0.6-2.3-0.6l-3.9,0l0,5.1L25.3,27.8z"/>
<path style="fill:#FFFFFF;" d="M36,33.2l-1.9,0l0-3.3l2.5,0l0.6-3.8l-2.3,0l0-3.3l2.8,0l0.6-3.7l3.4,0l-0.6,3.7l3.7,0l0.6-3.7
l3.4,0l-0.6,3.7l1.9,0l0,3.3l-2.5,0L47,29.9l2.3,0l0,3.3l-2.8,0L45.8,37l-3.4,0l0.7-3.8l-3.7,0L38.7,37l-3.4,0L36,33.2z
M43.7,29.9l0.6-3.8l-3.7,0L40,29.9L43.7,29.9z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -1,64 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 70 70" style="enable-background:new 0 0 70 70;" xml:space="preserve">
<g>
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="1.7738" y1="31.2729" x2="40.1662" y2="31.2729">
<stop offset="0" style="stop-color:#905CFB"/>
<stop offset="6.772543e-002" style="stop-color:#776CF9"/>
<stop offset="0.1729" style="stop-color:#5681F7"/>
<stop offset="0.2865" style="stop-color:#3B92F5"/>
<stop offset="0.4097" style="stop-color:#269FF4"/>
<stop offset="0.5474" style="stop-color:#17A9F3"/>
<stop offset="0.7111" style="stop-color:#0FAEF2"/>
<stop offset="0.9677" style="stop-color:#0CB0F2"/>
</linearGradient>
<path style="fill:url(#SVGID_1_);" d="M39.7,47.9l-6.1-34c-0.4-2.4-1.2-4.8-2.7-7.1c-2-3.2-5.2-5.4-8.8-6.3
C7.9-2.9-2.6,11.3,3.6,23.9c0,0,0,0,0,0l14.8,31.7c0.4,1,1,2,1.7,2.9c1.2,1.6,2.8,2.8,4.7,3.4C34.4,64.9,42.1,56.4,39.7,47.9z"/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="5.3113" y1="9.6691" x2="69.2278" y2="43.8664">
<stop offset="0" style="stop-color:#905CFB"/>
<stop offset="6.772543e-002" style="stop-color:#776CF9"/>
<stop offset="0.1729" style="stop-color:#5681F7"/>
<stop offset="0.2865" style="stop-color:#3B92F5"/>
<stop offset="0.4097" style="stop-color:#269FF4"/>
<stop offset="0.5474" style="stop-color:#17A9F3"/>
<stop offset="0.7111" style="stop-color:#0FAEF2"/>
<stop offset="0.9677" style="stop-color:#0CB0F2"/>
</linearGradient>
<path style="fill:url(#SVGID_2_);" d="M67.4,26.5c-1.4-2.2-3.4-3.9-5.7-4.9L25.5,1.7l0,0c-1-0.5-2.1-1-3.3-1.3
C6.7-3.2-4.4,13.8,5.5,27c1.5,2,3.6,3.6,6,4.5L48,47.9c0.8,0.5,1.6,0.8,2.5,1.1C64.5,53.4,75.1,38.6,67.4,26.5z"/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="-19.2836" y1="70.8198" x2="55.9833" y2="33.1863">
<stop offset="0" style="stop-color:#3BEA62"/>
<stop offset="0.117" style="stop-color:#31DE80"/>
<stop offset="0.3025" style="stop-color:#24CEA8"/>
<stop offset="0.4844" style="stop-color:#1AC1C9"/>
<stop offset="0.6592" style="stop-color:#12B7DF"/>
<stop offset="0.8238" style="stop-color:#0EB2ED"/>
<stop offset="0.9677" style="stop-color:#0CB0F2"/>
</linearGradient>
<path style="fill:url(#SVGID_3_);" d="M67.4,26.5c-1.8-2.8-4.6-4.8-7.9-5.6c-3.5-0.8-6.8-0.5-9.6,0.7L11.4,36.1
c0,0-0.2,0.1-0.6,0.4C0.9,40.4-4,53.3,4,64c1.8,2.4,4.3,4.2,7.1,5c5.3,1.6,10.1,1,14-1.1c0,0,0.1,0,0.1,0l37.6-20.1
c0,0,0,0,0.1-0.1C69.5,43.9,72.6,34.6,67.4,26.5z"/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="38.9439" y1="5.8503" x2="5.4232" y2="77.5093">
<stop offset="0" style="stop-color:#3BEA62"/>
<stop offset="9.397750e-002" style="stop-color:#2FDB87"/>
<stop offset="0.196" style="stop-color:#24CEA8"/>
<stop offset="0.3063" style="stop-color:#1BC3C3"/>
<stop offset="0.4259" style="stop-color:#14BAD8"/>
<stop offset="0.5596" style="stop-color:#10B5E7"/>
<stop offset="0.7185" style="stop-color:#0DB1EF"/>
<stop offset="0.9677" style="stop-color:#0CB0F2"/>
</linearGradient>
<path style="fill:url(#SVGID_4_);" d="M50.3,12.8c1.2-2.7,1.1-6-0.9-9c-1.1-1.8-2.9-3-4.9-3.5c-4.5-1.1-8.3,1-10.1,4.2L3.5,42
c0,0,0,0,0,0.1C-0.9,47.9-1.6,56.5,4,64c1.8,2.4,4.3,4.2,7.1,5c10.5,3.3,19.3-2.5,22.1-10.8L50.3,12.8z"/>
</g>
<g>
<rect x="13.4" y="13.4" style="fill:#000000;" width="43.2" height="43.2"/>
<rect x="17.5" y="48.5" style="fill:#FFFFFF;" width="16.2" height="2.7"/>
<polygon style="fill:#FFFFFF;" points="22.9,22.7 17.5,22.7 17.5,19.1 32.3,19.1 32.3,22.7 26.8,22.7 26.8,37 22.9,37 "/>
<path style="fill:#FFFFFF;" d="M32.5,28.1L32.5,28.1c0-5.1,3.8-9.3,9.3-9.3c3.4,0,5.4,1.1,7.1,2.8l-2.5,2.9c-1.4-1.3-2.8-2-4.6-2
c-3,0-5.2,2.5-5.2,5.6V28c0,3.1,2.1,5.6,5.2,5.6c2,0,3.3-0.8,4.7-2.1l2.5,2.5c-1.8,2-3.9,3.2-7.3,3.2
C36.4,37.3,32.5,33.2,32.5,28.1"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -1,81 +1,52 @@
# <img width="24px" src="./Logo/256.png" alt="Sonarr"></img> Sonarr
[![Translated](https://translate.servarr.com/widgets/servarr/-/sonarr/svg-badge.svg)](https://translate.servarr.com/engage/servarr/)
[![Backers on Open Collective](https://opencollective.com/Sonarr/backers/badge.svg)](#backers)
[![Sponsors on Open Collective](https://opencollective.com/Sonarr/sponsors/badge.svg)](#sponsors)
[![Mega Sponsors on Open Collective](https://opencollective.com/Sonarr/megasponsors/badge.svg)](#mega-sponsors)
# Sonarr
Sonarr is a PVR for Usenet and BitTorrent users. It can monitor multiple RSS feeds for new episodes of your favorite shows and will grab, sort and rename them. It can also be configured to automatically upgrade the quality of files already downloaded when a better quality format becomes available.
## Getting Started
## Major Features Include:
- [Download/Installation](https://sonarr.tv/#downloads-v3)
- [FAQ](https://wiki.servarr.com/sonarr/faq)
- [Wiki](https://wiki.servarr.com/Sonarr)
- [v4 Beta API Documentation](https://sonarr.tv/docs/api)
- [Donate](https://sonarr.tv/donate)
* Support for major platforms: Windows, Linux, macOS, Raspberry Pi, etc.
* Automatically detects new episodes
* Can scan your existing library and download any missing episodes
* Can watch for better quality of the episodes you already have and do an automatic upgrade. *eg. from DVD to Blu-Ray*
* Automatic failed download handling will try another release if one fails
* Manual search so you can pick any release or to see why a release was not downloaded automatically
* Fully configurable episode renaming
* Full integration with SABnzbd and NZBGet
* Full integration with Kodi, Plex (notification, library update, metadata)
* Full support for specials and multi-episode releases
* And a beautiful UI
## Support
## Configuring Development Environment:
Note: GitHub Issues are for Bugs and Feature Requests Only
### Requirements
- [Forums](https://forums.sonarr.tv/)
- [Discord](https://discord.gg/M6BvZn5)
- [GitHub - Bugs and Feature Requests Only](https://github.com/Sonarr/Sonarr/issues)
- [IRC](https://web.libera.chat/?channels=#sonarr)
- [Reddit](https://www.reddit.com/r/sonarr)
- [Wiki](https://wiki.servarr.com/sonarr)
* Visual Studio 2015 (https://www.visualstudio.com/vs/)
* [Git](https://git-scm.com/downloads)
* [NodeJS](https://nodejs.org/en/download/)
## Features
### Setup
### Current Features
* Make sure all the required software mentioned above are installed.
* Clone the repository into your development machine. [*info*](https://help.github.com/articles/working-with-repositories)
* Grab the submodules `git submodule init && git submodule update`
* Install the required Node Packages `npm install`
* Start gulp to monitor your dev environment for any changes that need post processing using `npm start` command.
- Support for major platforms: Windows, Linux, macOS, Raspberry Pi, etc.
- Automatically detects new episodes
- Can scan your existing library and download any missing episodes
- Can watch for better quality of the episodes you already have and do an automatic upgrade. *eg. from DVD to Blu-Ray*
- Automatic failed download handling will try another release if one fails
- Manual search so you can pick any release or to see why a release was not downloaded automatically
- Fully configurable episode renaming
- Full integration with SABnzbd and NZBGet
- Full integration with Kodi, Plex (notification, library update, metadata)
- Full support for specials and multi-episode releases
- And a beautiful UI
## Contributing
*Please note gulp must be running at all times while you are working with Sonarr client source files.*
### Development
This project exists thanks to all the people who contribute. [Contribute](CONTRIBUTING.md).
* Open `NzbDrone.sln` in Visual Studio
* Make sure `NzbDrone.Console` is set as the startup project
<a href="https://github.com/Sonarr/Sonarr/graphs/contributors"><img src="https://opencollective.com/Sonarr/contributors.svg?width=890&button=false" /></a>
### License
### Supporters
* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
* Copyright 2010-2017
This project would not be possible without the support of our users and software providers.
[**Become a sponsor or backer**](https://opencollective.com/sonarr) to help us out!
### Sponsors
#### Mega Sponsors
[![Sponsors](https://opencollective.com/sonarr/tiers/mega-sponsor.svg?width=890)](https://opencollective.com/sonarr/contribute/mega-sponsor-21443/checkout)
#### Sponsors
[![Flexible Sponsors](https://opencollective.com/sonarr/sponsors.svg?width=890)](https://opencollective.com/sonarr/contribute/sponsor-21457/checkout)
#### Backers
[![Backers](https://opencollective.com/sonarr/backers.svg?width=890)](https://opencollective.com/sonarr/contribute/backer-21442/checkout)
#### JetBrains
Thank you to [<img src="/Logo/Jetbrains/jetbrains.svg" alt="JetBrains" width="32"> JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools
* [<img src="/Logo/Jetbrains/teamcity.svg" alt="TeamCity" width="32"> TeamCity](http://www.jetbrains.com/teamcity/)
* [<img src="/Logo/Jetbrains/resharper.svg" alt="ReSharper" width="32"> ReSharper](http://www.jetbrains.com/resharper/)
* [<img src="/Logo/Jetbrains/dottrace.svg" alt="dotTrace" width="32"> dotTrace](http://www.jetbrains.com/dottrace/)
### Licenses
- [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
- Copyright 2010-2023
* [JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools
* [ReSharper](http://www.jetbrains.com/resharper/)
* [WebStorm](http://www.jetbrains.com/webstorm/)
* [TeamCity](http://www.jetbrains.com/teamcity/)

View File

@ -1,9 +0,0 @@
# Security Policy
## Reporting a Vulnerability
Please report (suspected) security vulnerabilities on Discord (preferred) to
either markus101
#2148 or Taloth#7357 or via email: security@sonarr.tv. You will receive a response from
us within 72 hours. If the issue is confirmed, we will release a patch as soon
as possible depending on complexity/severity.

568
build.sh
View File

@ -1,59 +1,119 @@
#! /usr/bin/env bash
set -e
#! /bin/bash
msBuildVersion='15.0'
outputFolder='./_output'
outputFolderLinux='./_output_linux'
outputFolderMacOS='./_output_macos'
outputFolderMacOSApp='./_output_macos_app'
testPackageFolder='./_tests/'
testSearchPattern='*.Test/bin/x86/Release'
sourceFolder='./src'
slnFile=$sourceFolder/Sonarr.sln
updateFolder=$outputFolder/Sonarr.Update
updateFolderMono=$outputFolderLinux/Sonarr.Update
outputFolder='_output'
testPackageFolder='_tests'
artifactsFolder="_artifacts";
framework="${FRAMEWORK:=net6.0}"
nuget='tools/nuget/nuget.exe';
vswhere='tools/vswhere/vswhere.exe';
. ./version.sh
CheckExitCode()
{
"$@"
local status=$?
if [ $status -ne 0 ]; then
echo "error with $1" >&2
exit 1
fi
return $status
}
ProgressStart()
{
echo "::group::$1"
echo "Start '$1'"
echo "##teamcity[blockOpened name='$1']"
echo "##teamcity[progressStart '$1']"
}
ProgressEnd()
{
echo "Finish '$1'"
echo "::endgroup::"
echo "##teamcity[progressFinish '$1']"
echo "##teamcity[blockClosed name='$1']"
}
UpdateVersionNumber()
{
if [ "$SONARR_VERSION" != "" ]; then
echo "Updating version info to: $SONARR_VERSION"
sed -i'' -e "s/<AssemblyVersion>[0-9.*]\+<\/AssemblyVersion>/<AssemblyVersion>$SONARR_VERSION<\/AssemblyVersion>/g" src/Directory.Build.props
sed -i'' -e "s/<AssemblyConfiguration>[\$()A-Za-z-]\+<\/AssemblyConfiguration>/<AssemblyConfiguration>${BRANCH}<\/AssemblyConfiguration>/g" src/Directory.Build.props
sed -i'' -e "s/<string>10.0.0.0<\/string>/<string>$SONARR_VERSION<\/string>/g" distribution/macOS/Sonarr.app/Contents/Info.plist
if [ "$BUILD_NUMBER" != "" ]; then
echo "Updating Version Info"
verMajorMinorRevision=`echo "$buildVersion" | cut -d. -f1,2,3`
verBuild=`echo "${BUILD_NUMBER}" | cut -d. -f4`
BUILD_NUMBER=$verMajorMinorRevision.$verBuild
echo "##teamcity[buildNumber '$BUILD_NUMBER']"
sed -i "s/^[[]assembly: Assembly\(File\|Informational\)\?Version[(]\"[0-9.*]\+\"[)]/[assembly: Assembly\1Version(\"$BUILD_NUMBER\")/g" ./src/NzbDrone*/Properties/AssemblyInfo.cs ./src/Sonarr*/Properties/AssemblyInfo.cs ./src/ServiceHelpers/*/Properties/AssemblyInfo.cs ./src/Common/CommonVersionInfo.cs
fi
}
EnableExtraPlatformsInSDK()
CreateReleaseInfo()
{
BUNDLEDVERSIONS="${SDK_PATH}/Microsoft.NETCoreSdk.BundledVersions.props"
if grep -q freebsd-x64 "$BUNDLEDVERSIONS"; then
echo "Extra platforms already enabled"
else
echo "Enabling extra platform support"
sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64/' "$BUNDLEDVERSIONS"
if [ "$BUILD_NUMBER" != "" ]; then
echo "Create Release Info"
echo -e "# Do Not Edit\nReleaseVersion=$BUILD_NUMBER\nBranch=${BRANCH:-dev}" > $outputFolder/release_info
fi
}
EnableExtraPlatforms()
CleanFolder()
{
if grep -qv freebsd-x64 src/Directory.Build.props; then
sed -i'' -e "s^<RuntimeIdentifiers>\(.*\)</RuntimeIdentifiers>^<RuntimeIdentifiers>\1;freebsd-x64</RuntimeIdentifiers>^g" src/Directory.Build.props
local path=$1
local keepConfigFiles=$2
find $path -name "*.transform" -exec rm "{}" \;
if [ $keepConfigFiles != true ] ; then
find $path -name "*.dll.config" -exec rm "{}" \;
fi
echo "Removing FluentValidation.Resources files"
find $path -name "FluentValidation.resources.dll" -exec rm "{}" \;
find $path -name "App.config" -exec rm "{}" \;
echo "Removing vshost files"
find $path -name "*.vshost.exe" -exec rm "{}" \;
echo "Removing dylib files"
find $path -name "*.dylib" -exec rm "{}" \;
echo "Removing Empty folders"
find $path -depth -empty -type d -exec rm -r "{}" \;
}
BuildWithMSBuild()
{
installationPath=`$vswhere -latest -products \* -requires Microsoft.Component.MSBuild -property installationPath`
installationPath=${installationPath/C:\\/\/c\/}
installationPath=${installationPath//\\/\/}
msBuild="$installationPath/MSBuild/$msBuildVersion/Bin"
echo $msBuild
export PATH=$msBuild:$PATH
CheckExitCode MSBuild.exe $slnFile //p:Configuration=Release //p:Platform=x86 //t:Clean //m
$nuget restore $slnFile
CheckExitCode MSBuild.exe $slnFile //p:Configuration=Release //p:Platform=x86 //t:Build //m //p:AllowedReferenceRelatedFileExtensions=.pdb
}
BuildWithXbuild()
{
export MONO_IOMAP=case
CheckExitCode xbuild /t:Clean $slnFile
mono $nuget restore $slnFile
CheckExitCode xbuild /p:Configuration=Release /p:Platform=x86 /t:Build /p:AllowedReferenceRelatedFileExtensions=.pdb $slnFile
}
LintUI()
{
ProgressStart 'ESLint'
yarn lint
CheckExitCode yarn eslint
ProgressEnd 'ESLint'
ProgressStart 'Stylelint'
yarn stylelint
CheckExitCode yarn stylelint
ProgressEnd 'Stylelint'
}
@ -62,394 +122,238 @@ Build()
ProgressStart 'Build'
rm -rf $outputFolder
rm -rf $testPackageFolder
slnFile=src/Sonarr.sln
if [ $os = "windows" ]; then
platform=Windows
if [ $runtime = "dotnet" ] ; then
BuildWithMSBuild
else
platform=Posix
BuildWithXbuild
fi
dotnet clean $slnFile -c Debug
dotnet clean $slnFile -c Release
CleanFolder $outputFolder false
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
then
dotnet msbuild -restore $slnFile -p:Configuration=Release -p:Platform=$platform -t:PublishAllRids
else
dotnet msbuild -restore $slnFile -p:Configuration=Release -p:Platform=$platform -p:RuntimeIdentifiers=$RID -t:PublishAllRids
fi
echo "Removing Mono.Posix.dll"
rm $outputFolder/Mono.Posix.dll
ProgressEnd 'Build'
}
YarnInstall()
RunGulp()
{
ProgressStart 'yarn install'
yarn install --frozen-lockfile --network-timeout 120000
yarn install
ProgressEnd 'yarn install'
LintUI
ProgressStart 'Running gulp'
CheckExitCode yarn run build --production
ProgressEnd 'Running gulp'
}
RunWebpack()
CreateMdbs()
{
ProgressStart 'Running webpack'
yarn run build --env production
ProgressEnd 'Running webpack'
}
PackageFiles()
{
local folder="$1"
local framework="$2"
local runtime="$3"
rm -rf $folder
mkdir -p $folder
cp -r $outputFolder/$framework/$runtime/publish/* $folder
cp -r $outputFolder/Sonarr.Update/$framework/$runtime/publish $folder/Sonarr.Update
if [ "$FRONTEND" = "YES" ];
then
cp -r $outputFolder/UI $folder
local path=$1
if [ $runtime = "dotnet" ] ; then
local pdbFiles=( $(find $path -name "*.pdb") )
for filename in "${pdbFiles[@]}"
do
if [ -e ${filename%.pdb}.dll ] ; then
tools/pdb2mdb/pdb2mdb.exe ${filename%.pdb}.dll
fi
if [ -e ${filename%.pdb}.exe ] ; then
tools/pdb2mdb/pdb2mdb.exe ${filename%.pdb}.exe
fi
done
fi
echo "Adding LICENSE"
cp LICENSE.md $folder
}
PackageLinux()
PackageMono()
{
local framework="$1"
local runtime="$2"
ProgressStart 'Creating Mono Package'
ProgressStart "Creating $runtime Package for $framework"
rm -rf $outputFolderLinux
local folder=$artifactsFolder/$runtime/$framework/Sonarr
echo "Copying Binaries"
cp -r $outputFolder $outputFolderLinux
PackageFiles "$folder" "$framework" "$runtime"
echo "Creating MDBs"
CreateMdbs $outputFolderLinux
echo "Removing PDBs"
find $outputFolderLinux -name "*.pdb" -exec rm "{}" \;
echo "Removing Service helpers"
rm -f $folder/ServiceUninstall.*
rm -f $folder/ServiceInstall.*
rm -f $outputFolderLinux/ServiceUninstall.*
rm -f $outputFolderLinux/ServiceInstall.*
echo "Removing native windows binaries Sqlite, MediaInfo"
rm -f $outputFolderLinux/sqlite3.*
rm -f $outputFolderLinux/MediaInfo.*
echo "Adding Sonarr.Core.dll.config (for dllmap)"
cp $sourceFolder/NzbDrone.Core/Sonarr.Core.dll.config $outputFolderLinux
echo "Adding CurlSharp.dll.config (for dllmap)"
cp $sourceFolder/NzbDrone.Common/CurlSharp.dll.config $outputFolderLinux
echo "Adding unix System.Runtime.InteropServices.RuntimeInformation.dll (for SharpRaven)"
cp $sourceFolder/packages/System.Runtime.InteropServices.RuntimeInformation.4.3.0/runtimes/unix/lib/netstandard1.1/System.Runtime.InteropServices.RuntimeInformation.dll $outputFolderLinux
cp $sourceFolder/packages/System.Runtime.InteropServices.RuntimeInformation.4.3.0/runtimes/unix/lib/netstandard1.1/System.Runtime.InteropServices.RuntimeInformation.dll $outputFolderLinux/Sonarr.Update
echo "Renaming Sonarr.Console.exe to Sonarr.exe"
rm $outputFolderLinux/Sonarr.exe*
for file in $outputFolderLinux/Sonarr.Console.exe*; do
mv "$file" "${file//.Console/}"
done
echo "Removing Sonarr.Windows"
rm $folder/Sonarr.Windows.*
rm $outputFolderLinux/Sonarr.Windows.*
echo "Adding Sonarr.Mono to UpdatePackage"
cp $folder/Sonarr.Mono.* $folder/Sonarr.Update
if [ "$framework" = "$framework" ]; then
cp $folder/Mono.Posix.NETStandard.* $folder/Sonarr.Update
cp $folder/libMonoPosixHelper.* $folder/Sonarr.Update
fi
cp $outputFolderLinux/Sonarr.Mono.* $updateFolderMono
ProgressEnd "Creating $runtime Package for $framework"
ProgressEnd 'Creating Mono Package'
}
PackageMacOS()
{
local framework="$1"
local runtime="$2"
ProgressStart 'Creating MacOS Package'
ProgressStart "Creating $runtime Package for $framework"
rm -rf $outputFolderMacOS
mkdir $outputFolderMacOS
local folder=$artifactsFolder/$runtime/$framework/Sonarr
echo "Adding Startup script"
cp ./macOS/Sonarr $outputFolderMacOS
dos2unix $outputFolderMacOS/Sonarr
PackageFiles "$folder" "$framework" "$runtime"
echo "Copying Binaries"
cp -r $outputFolderLinux/* $outputFolderMacOS
echo "Removing Service helpers"
rm -f $folder/ServiceUninstall.*
rm -f $folder/ServiceInstall.*
echo "Adding sqlite dylibs"
cp $sourceFolder/Libraries/Sqlite/*.dylib $outputFolderMacOS
echo "Removing Sonarr.Windows"
rm $folder/Sonarr.Windows.*
echo "Adding MediaInfo dylib"
cp $sourceFolder/Libraries/MediaInfo/*.dylib $outputFolderMacOS
echo "Adding Sonarr.Mono to UpdatePackage"
cp $folder/Sonarr.Mono.* $folder/Sonarr.Update
if [ "$framework" = "$framework" ]; then
cp $folder/Mono.Posix.NETStandard.* $folder/Sonarr.Update
cp $folder/libMonoPosixHelper.* $folder/Sonarr.Update
fi
ProgressEnd "Creating $runtime Package for $framework"
ProgressEnd 'Creating MacOS Package'
}
PackageMacOSApp()
{
local framework="$1"
local runtime="$2"
ProgressStart 'Creating macOS App Package'
ProgressStart "Creating $runtime App Package for $framework"
rm -rf $outputFolderMacOSApp
mkdir $outputFolderMacOSApp
cp -r ./macOS/Sonarr.app $outputFolderMacOSApp
mkdir -p $outputFolderMacOSApp/Sonarr.app/Contents/MacOS
local folder=$artifactsFolder/$runtime-app/$framework
rm -rf $folder
mkdir -p $folder
cp -r distribution/macOS/Sonarr.app $folder
mkdir -p $folder/Sonarr.app/Contents/MacOS
echo "Adding Startup script"
cp ./macOS/Sonarr $outputFolderMacOSApp/Sonarr.app/Contents/MacOS
dos2unix $outputFolderMacOSApp/Sonarr.app/Contents/MacOS/Sonarr
echo "Copying Binaries"
cp -r $artifactsFolder/$runtime/$framework/Sonarr/* $folder/Sonarr.app/Contents/MacOS
cp -r $outputFolderLinux/* $outputFolderMacOSApp/Sonarr.app/Contents/MacOS
echo "Adding sqlite dylibs"
cp $sourceFolder/Libraries/Sqlite/*.dylib $outputFolderMacOSApp/Sonarr.app/Contents/MacOS
echo "Adding MediaInfo dylib"
cp $sourceFolder/Libraries/MediaInfo/*.dylib $outputFolderMacOSApp/Sonarr.app/Contents/MacOS
echo "Removing Update Folder"
rm -r $folder/Sonarr.app/Contents/MacOS/Sonarr.Update
rm -r $outputFolderMacOSApp/Sonarr.app/Contents/MacOS/Sonarr.Update
ProgressEnd "Creating $runtime App Package for $framework"
}
PackageWindows()
{
local framework="$1"
local runtime="$2"
ProgressStart "Creating Windows Package for $framework"
local folder=$artifactsFolder/$runtime/$framework/Sonarr
PackageFiles "$folder" "$framework" "$runtime"
cp -r $outputFolder/$framework-windows/$runtime/publish/* $folder
echo "Removing Sonarr.Mono"
rm -f $folder/Sonarr.Mono.*
rm -f $folder/Mono.Posix.NETStandard.*
rm -f $folder/libMonoPosixHelper.*
echo "Adding Sonarr.Windows to UpdatePackage"
cp $folder/Sonarr.Windows.* $folder/Sonarr.Update
ProgressEnd "Creating Windows Package for $framework"
}
Package()
{
local framework="$1"
local runtime="$2"
local SPLIT
IFS='-' read -ra SPLIT <<< "$runtime"
case "${SPLIT[0]}" in
linux|freebsd*)
PackageLinux "$framework" "$runtime"
;;
win)
PackageWindows "$framework" "$runtime"
;;
osx)
PackageMacOS "$framework" "$runtime"
;;
esac
ProgressEnd 'Creating macOS App Package'
}
PackageTests()
{
local framework="$1"
local runtime="$2"
ProgressStart 'Creating Test Package'
ProgressStart "Creating $runtime Test Package for $framework"
rm -rf $testPackageFolder
mkdir $testPackageFolder
cp test.sh "$testPackageFolder/$framework/$runtime/publish"
find $sourceFolder -path $testSearchPattern -exec cp -r -u -T "{}" $testPackageFolder \;
rm -f $testPackageFolder/$framework/$runtime/*.log.config
if [ $runtime = "dotnet" ] ; then
$nuget install NUnit.ConsoleRunner -Version 3.2.0 -Output $testPackageFolder
else
mono $nuget install NUnit.ConsoleRunner -Version 3.2.0 -Output $testPackageFolder
fi
ProgressEnd "Creating $runtime Test Package for $framework"
cp $outputFolder/*.dll $testPackageFolder
cp ./test.sh $testPackageFolder
echo "Creating MDBs for tests"
CreateMdbs $testPackageFolder
rm -f $testPackageFolder/*.log.config
CleanFolder $testPackageFolder true
echo "Adding Sonarr.Core.dll.config (for dllmap)"
cp $sourceFolder/NzbDrone.Core/Sonarr.Core.dll.config $testPackageFolder
echo "Adding CurlSharp.dll.config (for dllmap)"
cp $sourceFolder/NzbDrone.Common/CurlSharp.dll.config $testPackageFolder
echo "Copying CurlSharp libraries"
cp $sourceFolder/ExternalModules/CurlSharp/libs/i386/* $testPackageFolder
ProgressEnd 'Creating Test Package'
}
UploadTestArtifacts()
CleanupWindowsPackage()
{
local framework="$1"
ProgressStart 'Cleaning Windows Package'
ProgressStart 'Publishing Test Artifacts'
echo "Removing Sonarr.Mono"
rm -f $outputFolder/Sonarr.Mono.*
# Tests
for dir in $testPackageFolder/$framework/*
do
local runtime=$(basename "$dir")
echo "##teamcity[publishArtifacts '$testPackageFolder/$framework/$runtime/publish/** => tests.$runtime.zip']"
done
echo "Adding Sonarr.Windows to UpdatePackage"
cp $outputFolder/Sonarr.Windows.* $updateFolder
ProgressEnd 'Publishing Test Artifacts'
ProgressEnd 'Cleaning Windows Package'
}
UploadArtifacts()
PublishArtifacts()
{
local framework="$1"
ProgressStart 'Publishing Artifacts'
# Tests
echo "##teamcity[publishArtifacts '_tests/** => tests.zip']"
# Releases
for dir in $artifactsFolder/*
do
local runtime=$(basename "$dir")
echo "##teamcity[publishArtifacts '$outputFolder/** => Sonarr.$BRANCH.$BUILD_NUMBER.windows.zip!Sonarr']"
echo "##teamcity[publishArtifacts '$outputFolderLinux/** => Sonarr.$BRANCH.$BUILD_NUMBER.linux.tar.gz!Sonarr']"
echo "##teamcity[publishArtifacts '$outputFolderMacOS/** => Sonarr.$BRANCH.$BUILD_NUMBER.macos.tar.gz!Sonarr']"
echo "##teamcity[publishArtifacts '$outputFolderMacOSApp/** => Sonarr.$BRANCH.$BUILD_NUMBER.macos.zip']"
echo "##teamcity[publishArtifacts '$artifactsFolder/$runtime/$framework/** => Sonarr.$BRANCH.$SONARR_VERSION.$runtime.zip']"
done
# Debian Package / Windows installer / macOS app
# Debian Package
echo "##teamcity[publishArtifacts 'distribution/** => distribution.zip']"
ProgressEnd 'Publishing Artifacts'
}
UploadUIArtifacts()
{
local framework="$1"
ProgressStart 'Publishing UI Artifacts'
# UI folder
echo "##teamcity[publishArtifacts '$outputFolder/UI/** => UI.zip']"
ProgressEnd 'Publishing UI Artifacts'
}
# Use mono or .net depending on OS
case "$(uname -s)" in
CYGWIN*|MINGW32*|MINGW64*|MSYS*)
# on windows, use dotnet
os="windows"
runtime="dotnet"
;;
*)
# otherwise use mono
os="posix"
runtime="mono"
;;
esac
POSITIONAL=()
if [ $# -eq 0 ]; then
echo "No arguments provided, building everything"
BACKEND=YES
FRONTEND=YES
PACKAGES=YES
LINT=YES
ENABLE_EXTRA_PLATFORMS=NO
ENABLE_EXTRA_PLATFORMS_IN_SDK=NO
fi
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
--backend)
BACKEND=YES
shift # past argument
;;
--enable-bsd|--enable-extra-platforms)
ENABLE_EXTRA_PLATFORMS=YES
shift # past argument
;;
--enable-extra-platforms-in-sdk)
ENABLE_EXTRA_PLATFORMS_IN_SDK=YES
shift # past argument
;;
-r|--runtime)
RID="$2"
shift # past argument
shift # past value
;;
-f|--framework)
FRAMEWORK="$2"
shift # past argument
shift # past value
;;
--frontend)
FRONTEND=YES
shift # past argument
;;
--packages)
PACKAGES=YES
shift # past argument
;;
--lint)
LINT=YES
shift # past argument
;;
--all)
BACKEND=YES
FRONTEND=YES
PACKAGES=YES
LINT=YES
shift # past argument
;;
*) # unknown option
POSITIONAL+=("$1") # save it in an array for later
shift # past argument
;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters
if [ "$ENABLE_EXTRA_PLATFORMS_IN_SDK" = "YES" ];
then
EnableExtraPlatformsInSDK
fi
if [ "$BACKEND" = "YES" ];
then
UpdateVersionNumber
if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ];
then
EnableExtraPlatforms
fi
Build
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
then
PackageTests "$framework" "win-x64"
PackageTests "$framework" "win-x86"
PackageTests "$framework" "linux-x64"
PackageTests "$framework" "linux-musl-x64"
PackageTests "$framework" "osx-x64"
if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ];
then
PackageTests "$framework" "freebsd-x64"
fi
else
PackageTests "$FRAMEWORK" "$RID"
fi
UploadTestArtifacts "$framework"
fi
if [ "$FRONTEND" = "YES" ];
then
YarnInstall
if [ "$LINT" = "YES" ];
then
LintUI
fi
RunWebpack
UploadUIArtifacts
fi
if [ "$PACKAGES" = "YES" ];
then
UpdateVersionNumber
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
then
Package "$framework" "win-x64"
Package "$framework" "win-x86"
Package "$framework" "linux-x64"
Package "$framework" "linux-musl-x64"
Package "$framework" "linux-arm64"
Package "$framework" "linux-musl-arm64"
Package "$framework" "linux-arm"
Package "$framework" "osx-x64"
Package "$framework" "osx-arm64"
if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ];
then
Package "$framework" "freebsd-x64"
fi
else
Package "$FRAMEWORK" "$RID"
fi
UploadArtifacts "$framework"
fi
UpdateVersionNumber
Build
CreateReleaseInfo
RunGulp
PackageMono
PackageMacOS
PackageMacOSApp
PackageTests
CleanupWindowsPackage
PublishArtifacts

View File

@ -1,7 +0,0 @@
# Note, this script is only used for local dev tests, this is not the script used for building the official sonarr package
mkdir -p /${PWD}/../_output_debian
docker build -f docker-build/Dockerfile -t sonarr-packager ./docker-build
docker run --rm -v /${PWD}/../_output_linux:/data/sonarr_bin:ro -v /${PWD}:/data/build -v /${PWD}/../_output_debian:/data/output sonarr-packager

47
distribution/debian.sh Normal file
View File

@ -0,0 +1,47 @@
fromdos ./debian/*
cp -r ./debian ./debian_backup
BuildVersion=${dependent_build_number:-3.10.0.999}
BuildBranch=${dependent_build_branch:-master}
BootstrapVersion=`echo "$BuildVersion" | cut -d. -f1,2,3`
BootstrapUpdater="BuiltIn"
PackageUpdater="apt"
echo Version: "$BuildVersion" Branch: "$BuildBranch"
rm -r ./sonarr_bin/Sonarr.Update
chmod -R ugo-x,ugo+rwX,go-w ./sonarr_bin/*
echo Updating changelog for $BuildVersion
sed -i "s:{version}:$BuildVersion:g; s:{branch}:$BuildBranch:g;" debian/changelog
sed -i "s:{version}:$BuildVersion:g; s:{updater}:$PackageUpdater:g" debian/preinst debian/postinst debian/postrm
sed -i '/#BEGIN BUILTIN UPDATER/,/#END BUILTIN UPDATER/d' debian/preinst debian/postinst debian/postrm
echo "# Do Not Edit\nPackageVersion=$BuildVersion\nReleaseVersion=$BuildVersion\nUpdateMethod=$PackageUpdater\nBranch=$BuildBranch" > package_info
echo Running debuild for $BuildVersion
debuild -b
# Restore debian directory to the original files
rm -rf ./debian
mv ./debian_backup ./debian
echo Updating changelog for $BootstrapVersion
sed -i "s:{version}:$BootstrapVersion:g; s:{branch}:$BuildBranch:g;" debian/changelog
sed -i "s:{version}:$BuildVersion:g; s:{updater}:$BootstrapUpdater:g" debian/preinst debian/postinst debian/postrm
sed -i '/#BEGIN BUILTIN UPDATER/d; /#END BUILTIN UPDATER/d' debian/preinst debian/postinst debian/postrm
echo "# Do Not Edit\nPackageVersion=$BootstrapVersion\nReleaseVersion=$BuildVersion\nUpdateMethod=$BootstrapUpdater\nBranch=$BuildBranch" > package_info
echo Running debuild for $BootstrapVersion
debuild -b
echo Moving stuff around
mv ../sonarr_*.deb ./
mv ../sonarr_*.changes ./
rm ../sonarr_*.build
echo Signing Package
dpkg-sig -k 884589CE --sign builder "sonarr_${BuildVersion}_all.deb"
dpkg-sig -k 884589CE --sign builder "sonarr_${BootstrapVersion}_all.deb"
echo running alien
alien -r -v ./*.deb

View File

@ -0,0 +1,6 @@
[*]
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2

View File

@ -0,0 +1,5 @@
sonarr ({version}) {branch}; urgency=low
* Automatic Release.
-- Sonarr <hello@sonarr.tv> Sun, 28 Jan 2018 00:00:00 -0700

View File

@ -0,0 +1 @@
8

View File

@ -0,0 +1,14 @@
#!/bin/sh -e
. /usr/share/debconf/confmodule
db_beginblock
db_input high sonarr/owning_user || true
db_input high sonarr/owning_group || true
db_endblock
db_go
db_input low sonarr/config_directory || true
db_go
exit 0

View File

@ -0,0 +1,21 @@
Section: web
Priority: optional
Maintainer: Sonarr <hello@sonarr.tv>
Source: sonarr
Homepage: https://sonarr.tv
Vcs-Git: git@github.com:Sonarr/Sonarr.git
Vcs-Browser: https://github.com/Sonarr/Sonarr
Build-Depends: debhelper (>= 9),
dh-systemd (>= 1.5),
mono-devel (>= 4.6),
libmono-cil-dev (>= 4.6),
cli-common-dev (>= 0.5.7)
Package: sonarr
Architecture: all
Provides: nzbdrone
Conflicts: nzbdrone
Replaces: nzbdrone
Depends: adduser, libsqlite3-0 (>= 3.7), libmediainfo0v5 (>= 0.7.52), mono-runtime (>= 5.4), ${cli:Depends}, ${misc:Depends}
Recommends: sqlite3 (>= 3.7), mediainfo (>= 0.7.52), ${cli:Recommends}
Description: Internet PVR

View File

@ -0,0 +1,24 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: sonarr
Source: https://github.com/Sonarr/Sonarr
Files: *
Copyright: 2010-2016 Sonarr <hello@sonarr.tv>
License: GPL-3.0+
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 package 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 <http://www.gnu.org/licenses/>.
.
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".

View File

@ -0,0 +1 @@
sonarr_3.0.0.0_all.deb web optional

View File

@ -0,0 +1,2 @@
sonarr_bin/* /usr/lib/sonarr/bin
package_info /usr/lib/sonarr

View File

@ -1,182 +0,0 @@
#!/bin/bash
### Description: Sonarr .NET Debian install
### Originally written for Radarr by: DoctorArr - doctorarr@the-rowlands.co.uk on 2021-10-01 v1.0
### Updates for servarr suite made by Bakerboy448, DoctorArr, brightghost, aeramor and VP-EN
### Version v1.0.0 2023-12-29 - StevieTV - adapted from servarr script for Sonarr installs
### Version V1.0.1 2024-01-02 - StevieTV - remove UTF8-BOM
### Version V1.0.2 2024-01-03 - markus101 - Get user input from /dev/tty
### Version V1.0.3 2024-01-06 - StevieTV - exit script when it is ran from install directory
### Boilerplate Warning
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
#MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
#LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
#OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
#WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
scriptversion="1.0.3"
scriptdate="2024-01-06"
set -euo pipefail
echo "Running Sonarr Install Script - Version [$scriptversion] as of [$scriptdate]"
# Am I root?, need root!
if [ "$EUID" -ne 0 ]; then
echo "Please run as root."
exit
fi
app="sonarr"
app_port="8989"
app_prereq="curl sqlite3 wget"
app_umask="0002"
branch="main"
# Constants
### Update these variables as required for your specific instance
installdir="/opt" # {Update me if needed} Install Location
bindir="${installdir}/${app^}" # Full Path to Install Location
datadir="/var/lib/$app/" # {Update me if needed} AppData directory to use
app_bin=${app^} # Binary Name of the app
# This script should not be ran from installdir, otherwise later in the script the extracted files will be removed before they can be moved to installdir.
if [ "$installdir" == "$(dirname -- "$( readlink -f -- "$0"; )")" ] || [ "$bindir" == "$(dirname -- "$( readlink -f -- "$0"; )")" ]; then
echo "You should not run this script from the intended install directory. The script will exit. Please re-run it from another directory"
exit
fi
# Prompt User
read -r -p "What user should ${app^} run as? (Default: $app): " app_uid < /dev/tty
app_uid=$(echo "$app_uid" | tr -d ' ')
app_uid=${app_uid:-$app}
# Prompt Group
read -r -p "What group should ${app^} run as? (Default: media): " app_guid < /dev/tty
app_guid=$(echo "$app_guid" | tr -d ' ')
app_guid=${app_guid:-media}
echo "This will install [${app^}] to [$bindir] and use [$datadir] for the AppData Directory"
echo "${app^} will run as the user [$app_uid] and group [$app_guid]. By continuing, you've confirmed that the selected user and group will have READ and WRITE access to your Media Library and Download Client Completed Download directories"
read -n 1 -r -s -p $'Press enter to continue or ctrl+c to exit...\n' < /dev/tty
# Create User / Group as needed
if [ "$app_guid" != "$app_uid" ]; then
if ! getent group "$app_guid" >/dev/null; then
groupadd "$app_guid"
fi
fi
if ! getent passwd "$app_uid" >/dev/null; then
adduser --system --no-create-home --ingroup "$app_guid" "$app_uid"
echo "Created and added User [$app_uid] to Group [$app_guid]"
fi
if ! getent group "$app_guid" | grep -qw "$app_uid"; then
echo "User [$app_uid] did not exist in Group [$app_guid]"
usermod -a -G "$app_guid" "$app_uid"
echo "Added User [$app_uid] to Group [$app_guid]"
fi
# Stop the App if running
if service --status-all | grep -Fq "$app"; then
systemctl stop "$app"
systemctl disable "$app".service
echo "Stopped existing $app"
fi
# Create Appdata Directory
# AppData
mkdir -p "$datadir"
chown -R "$app_uid":"$app_guid" "$datadir"
chmod 775 "$datadir"
echo "Directories created"
# Download and install the App
# prerequisite packages
echo ""
echo "Installing pre-requisite Packages"
# shellcheck disable=SC2086
apt update && apt install -y $app_prereq
echo ""
ARCH=$(dpkg --print-architecture)
# get arch
dlbase="https://services.sonarr.tv/v1/download/$branch/latest?version=4&os=linux"
case "$ARCH" in
"amd64") DLURL="${dlbase}&arch=x64" ;;
"armhf") DLURL="${dlbase}&arch=arm" ;;
"arm64") DLURL="${dlbase}&arch=arm64" ;;
*)
echo "Arch not supported"
exit 1
;;
esac
echo ""
echo "Removing previous tarballs"
# -f to Force so we fail if it doesn't exist
rm -f "${app^}".*.tar.gz
echo ""
echo "Downloading..."
wget --content-disposition "$DLURL"
tar -xvzf "${app^}".*.tar.gz
echo ""
echo "Installation files downloaded and extracted"
# remove existing installs
echo "Removing existing installation"
rm -rf "$bindir"
echo "Installing..."
mv "${app^}" $installdir
chown "$app_uid":"$app_guid" -R "$bindir"
chmod 775 "$bindir"
rm -rf "${app^}.*.tar.gz"
# Ensure we check for an update in case user installs older version or different branch
touch "$datadir"/update_required
chown "$app_uid":"$app_guid" "$datadir"/update_required
echo "App Installed"
# Configure Autostart
# Remove any previous app .service
echo "Removing old service file"
rm -rf /etc/systemd/system/"$app".service
# Create app .service with correct user startup
echo "Creating service file"
cat <<EOF | tee /etc/systemd/system/"$app".service >/dev/null
[Unit]
Description=${app^} Daemon
After=syslog.target network.target
[Service]
User=$app_uid
Group=$app_guid
UMask=$app_umask
Type=simple
ExecStart=$bindir/$app_bin -nobrowser -data=$datadir
TimeoutStopSec=20
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
# Start the App
echo "Service file created. Attempting to start the app"
systemctl -q daemon-reload
systemctl enable --now -q "$app"
# Finish Update/Installation
host=$(hostname -I)
ip_local=$(grep -oP '^\S*' <<<"$host")
echo ""
echo "Install complete"
sleep 10
STATUS="$(systemctl is-active "$app")"
if [ "${STATUS}" = "active" ]; then
echo "Browse to http://$ip_local:$app_port for the ${app^} GUI"
else
echo "${app^} failed to start"
fi
# Exit
exit 0

View File

@ -0,0 +1,107 @@
#!/bin/sh
set -e
BUILD_VERSION={version}
UPDATER={updater}
. /usr/share/debconf/confmodule
db_get sonarr/owning_user
USER="$RET"
db_get sonarr/owning_group
GROUP="$RET"
db_get sonarr/config_directory
CONFDIR="$RET"
# Add User and Group
if ! getent group "$GROUP" >/dev/null; then
groupadd "$GROUP"
fi
if ! getent passwd "$USER" >/dev/null; then
adduser --system --no-create-home --ingroup "$GROUP" "$USER"
fi
if [ $1 = "configure" ]; then
# Migrate old Sonarr v3 alpha data dir from /var/opt/sonarr or user home
if [ -d "/var/opt/sonarr" ] && [ "$CONFDIR" != "/var/opt/sonarr" ] && [ ! -d "$CONFDIR" ]; then
varoptRoot="/var/opt/sonarr"
varoptAppData="$varoptRoot/.config/Sonarr"
sonarrUserHome=`getent passwd $USER | cut -d ':' -f 6`
sonarrAppData="$sonarrUserHome/.config/Sonarr"
if [ -f "$varoptRoot/sonarr.db" ]; then
# Handle /var/opt/sonarr/sonarr.db
mv "$varoptRoot" "$CONFDIR"
elif [ -f "$varoptAppData/sonarr.db" ]; then
# Handle /var/opt/sonarr/.config/Sonarr/sonarr.db
mv "$varoptAppData" "$CONFDIR"
rm -rf "$varoptRoot"
elif [ -f "$sonarrAppData/sonarr.db" ]; then
# Handle ~/.config/Sonarr/sonarr.db
mv "$sonarrAppData" "$CONFDIR"
rm -rf "$sonarrAppData"
else
mv "$varoptRoot" "$CONFDIR"
fi
chown -R $USER:$GROUP "$CONFDIR"
chmod -R 775 "$CONFDIR"
fi
# Migrate old NzbDrone data dir
if [ -d "/usr/lib/sonarr/nzbdrone-appdata" ] && [ ! -d "$CONFDIR" ]; then
NZBDRONE_DATA=`readlink /usr/lib/sonarr/nzbdrone-appdata`
if [ -f "$NZBDRONE_DATA/config.xml" ] && [ -f "$NZBDRONE_DATA/nzbdrone.db" ]; then
echo "Found NzbDrone database in $NZBDRONE_DATA, copying to $CONFDIR."
mkdir -p "$CONFDIR"
cp $NZBDRONE_DATA/config.xml $NZBDRONE_DATA/nzbdrone.db* "$CONFDIR/"
chown -R $USER:$GROUP "$CONFDIR"
chmod -R 775 "$CONFDIR"
else
echo "Missing NzbDrone database in $NZBDRONE_DATA, skipping migration."
fi
rm /usr/lib/sonarr/nzbdrone-appdata
fi
fi
# Create data directory
if [ ! -d "$CONFDIR" ]; then
mkdir -p "$CONFDIR"
chown -R $USER:$GROUP "$CONFDIR"
fi
#BEGIN BUILTIN UPDATER
# Apply patch if present
if [ "$UPDATER" = "BuiltIn" ] && [ -f /usr/lib/sonarr/bin_patch/release_info ]; then
# It shouldn't be possible to get a wrong bin_patch, but let's check anyway and throw it away if it's wrong
currentVersion=`cat /usr/lib/sonarr/bin_patch/release_info | grep 'ReleaseVersion=' | cut -d= -f 2`
currentRelease=`echo "$currentVersion" | cut -d. -f1,2,3`
currentBuild=`echo "$currentVersion" | cut -d. -f4`
targetVersion=$BUILD_VERSION
targetRelease=`echo "$targetVersion" | cut -d. -f1,2,3`
targetBuild=`echo "$targetVersion" | cut -d. -f4`
if [ "$currentRelease" = "$targetRelease" ] && [ "$currentBuild" -gt "$targetBuild" ]; then
echo "Applying $currentVersion from BuiltIn updater instead of downgrading to $targetVersion"
rm -rf /usr/lib/sonarr/bin
mv /usr/lib/sonarr/bin_patch /usr/lib/sonarr/bin
else
rm -rf /usr/lib/sonarr/bin_patch
fi
fi
#END BUILTIN UPDATER
# Set permissions on /usr/lib/sonarr
chown -R $USER:$GROUP /usr/lib/sonarr
# Update sonarr.service file
sed -i "s:User=sonarr:User=$USER:g; s:Group=sonarr:Group=$GROUP:g; s:-data=/var/lib/sonarr:-data=$CONFDIR:g" /lib/systemd/system/sonarr.service
#BEGIN BUILTIN UPDATER
if [ $1 = "upgrade" ] && [ "$UPDATER" = "BuiltIn" ]; then
# If we upgraded, signal Sonarr to do an update check on startup instead of scheduled.
touch $CONFDIR/update_required
chown $USER:$GROUP $CONFDIR/update_required
fi
#END BUILTIN UPDATER
#DEBHELPER#
exit 0

View File

@ -0,0 +1,36 @@
#!/bin/sh
set -e
BUILD_VERSION={version}
UPDATER={updater}
if [ $1 = "abort-install" ]; then
# preinst was aborted, possibly due to NzbDrone still running.
# Nothing to do here
:
fi
# The bin directory is expected to be empty, unless the BuiltIn updater added files.
if [ $1 = "remove" ] && [ -d /usr/lib/sonarr/bin ]; then
rm -rf /usr/lib/sonarr/bin
fi
#BEGIN BUILTIN UPDATER
# Remove any existing patch if still present
if [ $1 = "remove" ] && [ -d /usr/lib/sonarr/bin_patch ]; then
rm -rf /usr/lib/sonarr/bin_patch
fi
#END BUILTIN UPDATER
# Purge the entire sonarr configuration directory.
# TODO: Maybe move a minimal backup to tmp?
if [ $1 = "purge" ] && [ -e /usr/share/debconf/confmodule ]; then
. /usr/share/debconf/confmodule
db_get sonarr/config_directory
CONFDIR="$RET"
if [ -d "$CONFDIR" ]; then
rm -rf "$CONFDIR"
fi
fi
#DEBHELPER#

View File

@ -0,0 +1,76 @@
#!/bin/sh
set -e
BUILD_VERSION={version}
UPDATER={updater}
# Deal with existing nzbdrone installs
#
# Existing nzbdrone packages do not have startup scripts and the process might still be running.
# If the user manually installed nzbdrone then the process might still be running too.
if [ $1 = "install" ]; then
psNzbDrone=`ps ax -o'user,pid,ppid,unit,args' | grep mono.*NzbDrone\\\\.exe || true`
if [ ! -z "$psNzbDrone" ]; then
# Get the user and optional systemd unit
psNzbDroneUser=`echo "$psNzbDrone" | tr -s ' ' | cut -d ' ' -f 1`
psNzbDroneUnit=`echo "$psNzbDrone" | tr -s ' ' | cut -d ' ' -f 4`
# Get the appdata from the cmdline or get it from the user dir
droneAppData=`echo "$psNzbDrone" | tr ' ' '\n' | grep -- "-data=" | cut -d= -f 2`
if [ "$droneAppData" = "" ]; then
droneUserHome=`getent passwd $psNzbDroneUser | cut -d ':' -f 6`
droneAppData="$droneUserHome/.config/NzbDrone"
fi
if [ "$psNzbDroneUnit" != "-" ] && [ -d /run/systemd/system ]; then
# The user used a systemd auto-startup for NzbDrone, we can deal with that.
echo "NzbDrone systemd startup detected at $psNzbDroneUnit, stopping and disabling..."
deb-systemd-invoke stop $psNzbDroneUnit >/dev/null
deb-systemd-invoke mask $psNzbDroneUnit >/dev/null
else
# We don't support auto migration for other startup methods, so bail.
# This leaves the sonarr package in an incomplete state.
echo "ps: $psNzbDrone"
echo "Error: An existing Sonarr v2 (NzbDrone) process is running. Remove the NzbDrone auto-startup prior to installing sonarr."
exit 1
fi
# We don't have the debconf configuration yet so we can't migrate the data.
# Instead we symlink so postinst knows where it's at.
if [ -f "/usr/lib/sonarr/nzbdrone-appdata" ]; then
rm "/usr/lib/sonarr/nzbdrone-appdata"
else
mkdir -p "/usr/lib/sonarr"
fi
ln -s $droneAppData /usr/lib/sonarr/nzbdrone-appdata
fi
fi
#BEGIN BUILTIN UPDATER
# Check for supported upgrade paths
if [ $1 = "upgrade" ] && [ "$UPDATER" = "BuiltIn" ] && [ -f /usr/lib/sonarr/bin/release_info ]; then
# If we allow the Built-In updater to upgrade from 3.0.1.123 to 3.0.2.500 and now apt is catching up to 3.0.2.425
# then we need to deal with that 500->425 'downgrade'.
# We do that by preserving the binaries and using those instead for postinst.
currentVersion=`cat /usr/lib/sonarr/bin/release_info | grep 'ReleaseVersion=' | cut -d= -f 2`
currentRelease=`echo "$currentVersion" | cut -d. -f1,2,3`
currentBuild=`echo "$currentVersion" | cut -d. -f4`
targetVersion=$BUILD_VERSION
targetRelease=`echo "$targetVersion" | cut -d. -f1,2,3`
targetBuild=`echo "$targetVersion" | cut -d. -f4`
if [ -d /usr/lib/sonarr/bin_patch ]; then
rm -rf /usr/lib/sonarr/bin_patch
fi
# Check if the existing version is already an upgrade for the included build
if [ "$currentRelease" = "$targetRelease" ] && [ "$currentBuild" -gt "$targetBuild" ]; then
echo "Preserving $currentVersion from BuiltIn updater instead of downgrading to $targetVersion"
cp -r /usr/lib/sonarr/bin /usr/lib/sonarr/bin_patch
fi
fi
#END BUILTIN UPDATER
#DEBHELPER#
exit 0

29
distribution/debian/rules Normal file
View File

@ -0,0 +1,29 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
# Note: System.Native is a dependency of System.Runtime.InteropServices.RuntimeInformation used by SharpRaven,
# but SharpRaven doesn't use any functions that need System.Native
EXCLUDE_MODULEREFS = crypt32 httpapi System.Native
%:
dh $@ --with=systemd --with=cli
# No init script, only systemd
override_dh_installinit:
true
# Sonarr like debug symbols for logging
override_dh_clistrip:
override_dh_makeclilibs:
override_dh_clideps:
dh_clideps -d -r $(patsubst %,--exclude-moduleref=%,$(EXCLUDE_MODULEREFS))

View File

@ -0,0 +1,2 @@
recommends libcurl3
ignores msbuild

View File

@ -1,6 +1,3 @@
# This file is owned by the sonarr package, DO NOT MODIFY MANUALLY
# Instead use 'dpkg-reconfigure -plow sonarr' to modify User/Group/UMask/-data
# Or use systemd built-in override functionality using 'systemctl edit sonarr'
[Unit]
Description=Sonarr Daemon
After=network.target
@ -11,7 +8,7 @@ Group=sonarr
UMask=002
Type=simple
ExecStart=/opt/Sonarr/Sonarr -nobrowser -data=/var/lib/sonarr
ExecStart=/usr/bin/mono --debug /usr/lib/sonarr/bin/Sonarr.exe -nobrowser -data=/var/lib/sonarr
TimeoutStopSec=20
KillMode=process
Restart=on-failure

View File

@ -0,0 +1,21 @@
Template: sonarr/owning_user
Type: string
Default: sonarr
Description: Sonarr user:
Specify the user that is used to run Sonarr. The user will be created if it does not already exist.
The default 'sonarr' should work fine for most users. You can specify the user group next.
Template: sonarr/owning_group
Type: string
Default: sonarr
Description: Sonarr group:
Specify the group that is used to run Sonarr. The group will be created if it does not already exist.
If the user doesn't already exist then this group will be used as the user's primary group.
Any media files created by Sonarr will be writeable by this group.
It's advisable to keep the group the same between download client, Sonarr and media centers.
Template: sonarr/config_directory
Type: string
Default: /var/lib/sonarr
Description: Config directory:
Specify the directory where Sonarr stores the internal database and metadata. Media content will be stored elsewhere.

View File

@ -1,32 +0,0 @@
FROM ubuntu:focal AS builder
ENV DEBIAN_FRONTEND noninteractive
ENV MONO_VERSION 5.18
RUN apt-get update && \
apt-get -y -o Dpkg::Options::="--force-confold" install --no-install-recommends \
apt-transport-https \
wget dirmngr gpg gpg-agent \
# add-apt-repository for PPAs
software-properties-common && \
rm -rf /var/lib/apt/lists/*
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF && \
echo "deb http://download.mono-project.com/repo/debian stable-focal main" > /etc/apt/sources.list.d/mono-official-stable.list && \
apt-get update && apt-get install -y \
devscripts build-essential tofrodos \
dh-make dh-systemd \
cli-common-dev \
mono-complete \
sqlite3 libcurl4 mediainfo
RUN apt-get upgrade -y
RUN apt-cache policy mono-complete
RUN apt-cache policy cli-common-dev
COPY debian-start.sh /debian-start.sh
RUN fromdos /debian-start.sh
WORKDIR /data
VOLUME [ "/data/sonarr_bin", "/data/build", "/data/output" ]
CMD /debian-start.sh

View File

@ -1,18 +0,0 @@
echo "Debian Build Dev bootstrap..."
export TEST_OUTPUT=/data/output
mkdir ${TEST_OUTPUT}
mkdir /data/temp
cp -rf /data/build/debian.sh /data/temp
cp -rf /data/build/debian /data/temp
cp -rf /data/sonarr_bin /data/temp/sonarr_bin
cd /data/temp
ls -al .
fromdos debian.sh
sh debian.sh

View File

@ -1,7 +0,0 @@
@REM SET SONARR_MAJOR_VERSION=4
@REM SET SONARR_VERSION=4.0.0.5
@REM SET BRANCH=develop
@REM SET FRAMEWORK=net6.0
@REM SET RUNTIME=win-x64
inno\ISCC.exe sonarr.iss

View File

@ -1,86 +0,0 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define AppName "Sonarr"
#define AppPublisher "Team Sonarr"
#define AppURL "https://sonarr.tv/"
#define ForumsURL "https://forums.sonarr.tv/"
#define AppExeName "Sonarr.exe"
#define BuildNumber "4.0"
#define BuildNumber GetEnv('SONARR_VERSION')
#define MajorVersion GetEnv('SONARR_MAJOR_VERSION')
#define BranchName GetEnv('BRANCH')
#define Framework GetEnv('FRAMEWORK')
#define Runtime GetEnv('RUNTIME')
[Setup]
; NOTE: The value of AppId uniquely identifies this appl ication.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{56C1065D-3523-4025-B76D-6F73F67F7F71}
AppName={#AppName}
AppVersion={#MajorVersion}
AppPublisher={#AppPublisher}
AppPublisherURL={#AppURL}
AppSupportURL={#ForumsURL}
AppUpdatesURL={#AppURL}
UsePreviousAppDir=no
DefaultDirName={commonappdata}\Sonarr\bin
DisableDirPage=yes
DefaultGroupName={#AppName}
DisableProgramGroupPage=yes
OutputBaseFilename=Sonarr.{#BranchName}.{#BuildNumber}.{#Runtime}-installer
SolidCompression=yes
AppCopyright=Creative Commons 3.0 License
AllowUNCPath=False
UninstallDisplayIcon={app}\Sonarr.exe
DisableReadyPage=True
CompressionThreads=2
Compression=lzma2/normal
AppContact={#ForumsURL}
VersionInfoVersion={#MajorVersion}
SetupLogging=yes
OutputDir="..\..\..\_artifacts"
AppverName={#AppName}
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopIcon"; Description: "{cm:CreateDesktopIcon}"
Name: "windowsService"; Description: "Install Windows Service (Starts when the computer starts as the LocalService user, you will need to change the user to access network shares)"; GroupDescription: "Start automatically"; Flags: exclusive unchecked
Name: "startupShortcut"; Description: "Create shortcut in Startup folder (Starts when you log into Windows)"; GroupDescription: "Start automatically"; Flags: exclusive
Name: "none"; Description: "Do not start automatically"; GroupDescription: "Start automatically"; Flags: exclusive unchecked
[Files]
Source: "..\..\..\_output\{#Runtime}\{#Framework}\Sonarr\Sonarr.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\..\..\_output\{#Runtime}\{#Framework}\Sonarr\*"; Excludes: "Sonarr.Update"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{group}\{#AppName}"; Filename: "{app}\{#AppExeName}"; Parameters: "/icon"
Name: "{commondesktop}\{#AppName}"; Filename: "{app}\{#AppExeName}"; Parameters: "/icon"; Tasks: desktopIcon
Name: "{userstartup}\{#AppName}"; Filename: "{app}\Sonarr.exe"; WorkingDir: "{app}"; Tasks: startupShortcut
[InstallDelete]
Name: "{commonappdata}\NzbDrone\bin"; Type: filesandordirs
Name: "{app}"; Type: filesandordirs
[Run]
Filename: "{app}\Sonarr.Console.exe"; StatusMsg: "Removing previous Windows Service"; Parameters: "/u /exitimmediately"; Flags: runhidden waituntilterminated;
Filename: "{app}\Sonarr.Console.exe"; Description: "Enable Access from Other Devices"; StatusMsg: "Enabling Remote access"; Parameters: "/registerurl /exitimmediately"; Flags: postinstall runascurrentuser runhidden waituntilterminated; Tasks: startupShortcut none;
Filename: "{app}\Sonarr.Console.exe"; StatusMsg: "Installing Windows Service"; Parameters: "/i /exitimmediately"; Flags: runhidden waituntilterminated; Tasks: windowsService
Filename: "{app}\Sonarr.exe"; Description: "Open Sonarr Web UI"; Flags: postinstall skipifsilent nowait; Tasks: windowsService;
Filename: "{app}\Sonarr.exe"; Description: "Start Sonarr"; Flags: postinstall skipifsilent nowait; Tasks: startupShortcut none;
[UninstallRun]
Filename: "{app}\Sonarr.Console.exe"; Parameters: "/u"; Flags: runhidden waituntilterminated skipifdoesntexist
[Code]
function PrepareToInstall(var NeedsRestart: Boolean): String;
var
ResultCode: Integer;
begin
Exec('net', 'stop nzbdrone', '', 0, ewWaitUntilTerminated, ResultCode)
Exec('sc', 'delete nzbdrone', '', 0, ewWaitUntilTerminated, ResultCode)
end;

View File

@ -1,25 +0,0 @@
FROM ubuntu:xenial
ENV DEBIAN_FRONTEND noninteractive
ARG MONO_VERSION=5.20
ARG MONO_URL=stable-xenial/snapshots/$MONO_VERSION
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF && \
echo "deb http://download.mono-project.com/repo/debian $MONO_URL main" > /etc/apt/sources.list.d/mono-official-stable.list && \
apt-get update && apt-get install -y \
tofrodos tzdata \
mono-complete \
sqlite3 mediainfo \
&& rm -rf /var/lib/apt/lists/*
COPY startup.sh /startup.sh
RUN fromdos /startup.sh
WORKDIR /data/
VOLUME ["/data/_tests_linux", "/data/_output_linux", "/data/_tests_results"]
RUN groupadd sonarrtst -g 4020 && useradd sonarrtst -u 4021 -g 4020 -m -s /bin/bash
USER sonarrtst
CMD bash /startup.sh

View File

@ -1,32 +0,0 @@
FROM ubuntu:xenial
ENV DEBIAN_FRONTEND noninteractive
ARG MONO_VERSION=5.20
ARG MONO_URL=stable-xenial/snapshots/$MONO_VERSION
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF && \
echo "deb http://download.mono-project.com/repo/debian $MONO_URL main" > /etc/apt/sources.list.d/mono-official-stable.list && \
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 2009837CBFFD68F45BC180471F4F90DE2A9B4BF8 && \
echo "deb http://apt.sonarr.tv/ubuntu xenial main" > /etc/apt/sources.list.d/sonarr.list && \
apt-get update && apt-get install -y \
tofrodos tzdata \
sonarr \
sqlite3 mediainfo \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y \
libmono-system-runtime4.0-cil \
libmono-system-net-http4.0-cil \
&& rm -rf /var/lib/apt/lists/*
COPY startup.sh /startup.sh
RUN fromdos /startup.sh
WORKDIR /data/
VOLUME ["/data/_tests_linux", "/data/_output_linux", "/data/_tests_results"]
RUN groupadd sonarrtst -g 4020 && useradd sonarrtst -u 4021 -g 4020 -m -s /bin/bash
USER sonarrtst
CMD bash /startup.sh

View File

@ -1,15 +0,0 @@
echo "Preparing Test..."
mkdir -p /data/test
cp -r /data/_tests_linux/* /data/test/
cp -r /data/_output_linux /data/test/bin
cd /data/test
runTest()
{
bash test.sh Linux $1
cp TestResult.xml /data/_tests_results/TestResult_$1.xml
}
runTest Integration
runTest Unit

View File

@ -1,121 +0,0 @@
opt_parallel=
opt_version=
opt_mode=both
while getopts 'pv:m:r?h' c
do
case $c in
p) opt_parallel=1 ;;
v) opt_version=$OPTARG ;;
m) opt_mode=$OPTARG ;;
r) opt_report=1 ;;
?|h) printf "Usage: %s [-p] [-v mono-ver] [-m sonarr|complete]\n" $0
printf " -p run parallel\n"
printf " -v run specified mono version\n"
printf " -m run only mono-'complete' or 'sonarr' package variants\n"
printf " -r only report\n"
exit 2
esac
done
# NOTE:
# each container has a 1gb tmpfs mounted since it greatly speeds up the normally intensive db operations
# make sure that the docker host has enough memory to handle about ~300 MB per container, so 2-3 GB total
# excess goes to the swap and will slow down the entire system
MONO_VERSIONS=""
# Future versions
MONO_VERSIONS="$MONO_VERSIONS 6.10=preview-xenial"
# Semi-Supported versions
MONO_VERSIONS="$MONO_VERSIONS 6.8 6.6 6.4 6.0"
# Supported versions
MONO_VERSIONS="$MONO_VERSIONS 5.20 5.18"
# Legacy unsupported versions (but appear to work)
MONO_VERSIONS="$MONO_VERSIONS 5.16 5.14 5.12"
# Legacy unsupported versions
MONO_VERSIONS="$MONO_VERSIONS 5.10 5.8 5.4 5.0"
#MONO_VERSIONS="$MONO_VERSIONS 4.8=stable-wheezy/snapshots/4.8"
if [ "$opt_version" != "" ]; then
MONO_VERSIONS="$opt_version"
fi
mkdir -p ${PWD}/../../_tests_results
prepOne() {
local MONO_VERSION_PAIR=$1
MONO_VERSION_SPLIT=(${MONO_VERSION_PAIR//=/ })
MONO_VERSION=${MONO_VERSION_SPLIT[0]}
MONO_URL=${MONO_VERSION_SPLIT[1]:-"stable-xenial/snapshots/$MONO_VERSION"}
echo "Building Test Docker for mono $MONO_VERSION"
if [ "$opt_mode" != "sonarr" ]; then
docker build -t sonarr-test-$MONO_VERSION --build-arg MONO_VERSION=$MONO_VERSION --build-arg MONO_URL=$MONO_URL --file mono/complete/Dockerfile mono
fi
if [ "$opt_mode" != "complete" ] && [ "$MONO_VERSION" != "5.0" ]; then
docker build -t sonarr-test-$MONO_VERSION-sonarr --build-arg MONO_VERSION=$MONO_VERSION --build-arg MONO_URL=$MONO_URL --file mono/sonarr/Dockerfile mono
fi
}
runOne() {
local MONO_VERSION_PAIR=$1
MONO_VERSION_SPLIT=(${MONO_VERSION_PAIR//=/ })
MONO_VERSION=${MONO_VERSION_SPLIT[0]}
echo "Running Test Docker for mono $MONO_VERSION"
if [ "$opt_mode" != "sonarr" ]; then
dockerArgs="--rm"
dockerArgs="$dockerArgs -v /${PWD}/../../_tests_linux:/data/_tests_linux:ro"
dockerArgs="$dockerArgs -v /${PWD}/../../_output_linux:/data/_output_linux:ro"
dockerArgs="$dockerArgs -v /${PWD}/../../_tests_results/mono-$MONO_VERSION:/data/_tests_results"
dockerArgs="$dockerArgs --mount type=tmpfs,destination=//data/test,tmpfs-size=1g"
docker run $dockerArgs sonarr-test-$MONO_VERSION
fi
if [ "$opt_mode" != "complete" ] && [ "$MONO_VERSION" != "5.0" ]; then
dockerArgs="--rm"
dockerArgs="$dockerArgs -v /${PWD}/../../_tests_linux:/data/_tests_linux:ro"
dockerArgs="$dockerArgs -v /${PWD}/../../_output_linux:/data/_output_linux:ro"
dockerArgs="$dockerArgs -v /${PWD}/../../_tests_results/mono-$MONO_VERSION-sonarr:/data/_tests_results"
dockerArgs="$dockerArgs --mount type=tmpfs,destination=//data/test,tmpfs-size=1g"
docker run $dockerArgs sonarr-test-$MONO_VERSION-sonarr
fi
echo "Finished Test Docker for mono $MONO_VERSION"
}
if [ "$opt_report" != "1" ]; then
if [ "$opt_parallel" == "1" ]; then
for MONO_VERSION_PAIR in $MONO_VERSIONS; do
prepOne "$MONO_VERSION_PAIR"
done
fi
for MONO_VERSION_PAIR in $MONO_VERSIONS; do
if [ "$opt_parallel" == "1" ]; then
runOne "$MONO_VERSION_PAIR" &
else
prepOne "$MONO_VERSION_PAIR"
runOne "$MONO_VERSION_PAIR"
fi
done
if [ "$opt_parallel" == "1" ]; then
echo "Waiting for all runs to finish"
wait
echo "Finished all runs"
fi
fi
grep "<test-run" ../../_tests_results/**/*.xml | sed -r 's/.*?mono-([0-9.]+(-s)?).*?_([IU]).*?\.xml.*?failed="([0-9]*)".*/\1\t\3:\tfailed \4/g' | sort -V -t.

48
docs.sh
View File

@ -1,48 +0,0 @@
#!/bin/bash
set -e
FRAMEWORK="net6.0"
PLATFORM=$1
if [ "$PLATFORM" = "Windows" ]; then
RUNTIME="win-x64"
elif [ "$PLATFORM" = "Linux" ]; then
RUNTIME="linux-x64"
elif [ "$PLATFORM" = "Mac" ]; then
RUNTIME="osx-x64"
else
echo "Platform must be provided as first argument: Windows, Linux or Mac"
exit 1
fi
outputFolder='_output'
testPackageFolder='_tests'
rm -rf $outputFolder
rm -rf $testPackageFolder
slnFile=src/Sonarr.sln
platform=Posix
if [ "$PLATFORM" = "Windows" ]; then
application=Sonarr.Console.dll
else
application=Sonarr.dll
fi
dotnet clean $slnFile -c Debug
dotnet clean $slnFile -c Release
dotnet msbuild -restore $slnFile -p:Configuration=Debug -p:Platform=$platform -p:RuntimeIdentifiers=$RUNTIME -t:PublishAllRids
dotnet new tool-manifest
dotnet tool install --version 6.6.2 Swashbuckle.AspNetCore.Cli
dotnet tool run swagger tofile --output ./src/Sonarr.Api.V3/openapi.json "$outputFolder/$FRAMEWORK/$RUNTIME/$application" v3 &
sleep 45
kill %1
exit 0

25
frontend/.csscomb.json Normal file
View File

@ -0,0 +1,25 @@
{
"remove-empty-rulesets": true,
"always-semicolon": true,
"color-case": "lower",
"block-indent": " ",
"color-shorthand": false,
"element-case": "lower",
"eof-newline": true,
"leading-zero": true,
"quotes": "double",
"sort-order-fallback": "abc",
"space-before-colon": "",
"space-after-colon": " ",
"space-before-combinator": " ",
"space-after-combinator": " ",
"space-between-declarations": "\n",
"space-before-opening-brace": " ",
"space-after-opening-brace": "\n",
"space-after-selector-delimiter": " ",
"space-before-selector-delimiter": "",
"space-before-closing-brace": "\n",
"strip-spaces": true,
"tab-size": true,
"unitless-zero": false
}

335
frontend/.esformatter Normal file
View File

@ -0,0 +1,335 @@
{
"indent": {
"value": " ",
"FunctionExpression": 1,
"ArrayExpression": 1,
"ObjectExpression": 1
},
"lineBreak": {
"value": "\n",
"before": {
"ArrayPatternClosing": 0,
"ArrayPatternComma": 0,
"ArrayPatternOpening": 0,
"ArrowFunctionExpressionArrow": 0,
"ArrowFunctionExpressionClosingBrace": ">=1",
"ArrowFunctionExpressionOpeningBrace": 0,
"AssignmentExpression": ">=1",
"AssignmentOperator": 0,
"BlockStatement": 0,
"BreakKeyword": ">=1",
"CallExpression": -1,
"CallExpressionClosingParentheses": -1,
"CallExpressionOpeningParentheses": 0,
"CatchClosingBrace": ">=1",
"CatchKeyword": 0,
"CatchOpeningBrace": 0,
"ClassDeclaration": ">=1",
"ClassDeclarationClosingBrace": ">=1",
"ClassDeclarationOpeningBrace": 0,
"ConditionalExpression": ">=1",
"DeleteOperator": ">=1",
"DoWhileStatement": ">=1",
"DoWhileStatementClosingBrace": ">=1",
"DoWhileStatementOpeningBrace": 0,
"ElseIfStatement": 0,
"ElseIfStatementClosingBrace": ">=1",
"ElseIfStatementOpeningBrace": 0,
"ElseStatement": 0,
"ElseStatementClosingBrace": ">=1",
"ElseStatementOpeningBrace": 0,
"EmptyStatement": -1,
"EndOfFile": -1,
"FinallyClosingBrace": ">=1",
"FinallyKeyword": -1,
"FinallyOpeningBrace": 0,
"ForInStatement": ">=1",
"ForInStatementClosingBrace": ">=1",
"ForInStatementExpressionClosing": 0,
"ForInStatementExpressionOpening": 0,
"ForInStatementOpeningBrace": 0,
"ForStatement": ">=1",
"ForStatementClosingBrace": ">=1",
"ForStatementExpressionClosing": "<2",
"ForStatementExpressionOpening": 0,
"ForStatementOpeningBrace": 0,
"FunctionDeclaration": ">=1",
"FunctionDeclarationClosingBrace": ">=1",
"FunctionDeclarationOpeningBrace": 0,
"FunctionExpression": 0,
"FunctionExpressionClosingBrace": 1,
"FunctionExpressionOpeningBrace":0,
"IIFEClosingParentheses": 0,
"IfStatement": ">=1",
"IfStatementClosingBrace": ">=1",
"IfStatementOpeningBrace": 0,
"LogicalExpression": -1,
"MemberExpressionClosing": 0,
"MemberExpressionOpening": 0,
"MemberExpressionPeriod": -1,
"MethodDefinition": ">=1",
"ObjectExpressionClosingBrace": "<=1",
"ObjectPatternClosingBrace": 0,
"ObjectPatternComma": 0,
"ObjectPatternOpeningBrace": 0,
"ParameterDefault": 0,
"Property": "<=2",
"PropertyValue": 0,
"ReturnStatement": -1,
"SwitchClosingBrace": ">=1",
"SwitchOpeningBrace": 0,
"ThisExpression": -1,
"ThrowStatement": ">=1",
"TryClosingBrace": ">=1",
"TryKeyword": -1,
"TryOpeningBrace": 0,
"VariableDeclaration": ">=1",
"VariableDeclarationSemiColon": 0,
"VariableDeclarationWithoutInit": ">=1",
"VariableName": ">=1",
"VariableValue": 0,
"WhileStatement": ">=1",
"WhileStatementClosingBrace": ">=1",
"WhileStatementOpeningBrace": 0
},
"after": {
"ArrayPatternClosing": 0,
"ArrayPatternComma": 0,
"ArrayPatternOpening": 0,
"ArrowFunctionExpressionArrow": 0,
"ArrowFunctionExpressionClosingBrace": -1,
"ArrowFunctionExpressionOpeningBrace": ">=1",
"AssignmentExpression": ">=1",
"AssignmentOperator": 0,
"BlockStatement": 0,
"BreakKeyword": -1,
"CallExpression": -1,
"CallExpressionClosingParentheses": -1,
"CallExpressionOpeningParentheses": -1,
"CatchClosingBrace": ">=0",
"CatchKeyword": 0,
"CatchOpeningBrace": ">=1",
"ClassDeclaration": ">=1",
"ClassDeclarationClosingBrace": ">=1",
"ClassDeclarationOpeningBrace": ">=1",
"ConditionalExpression": ">=1",
"DeleteOperator": ">=1",
"DoWhileStatement": ">=1",
"DoWhileStatementClosingBrace": 0,
"DoWhileStatementOpeningBrace": ">=1",
"ElseIfStatement": ">=1",
"ElseIfStatementClosingBrace": ">=1",
"ElseIfStatementOpeningBrace": ">=1",
"ElseStatement": ">=1",
"ElseStatementClosingBrace": ">=1",
"ElseStatementOpeningBrace": ">=1",
"EmptyStatement": -1,
"FinallyClosingBrace": ">=1",
"FinallyKeyword": -1,
"FinallyOpeningBrace": ">=1",
"ForInStatement": ">=1",
"ForInStatementClosingBrace": ">=1",
"ForInStatementExpressionClosing": -1,
"ForInStatementExpressionOpening": "<2",
"ForInStatementOpeningBrace": ">=1",
"ForStatement": ">=1",
"ForStatementClosingBrace": ">=1",
"ForStatementExpressionClosing": -1,
"ForStatementExpressionOpening": "<2",
"ForStatementOpeningBrace": ">=1",
"FunctionDeclaration": ">=1",
"FunctionDeclarationClosingBrace": ">=1",
"FunctionDeclarationOpeningBrace": ">=1",
"FunctionExpression": 0,
"FunctionExpressionClosingBrace": -1,
"FunctionExpressionOpeningBrace": 1,
"IIFEOpeningParentheses": 0,
"IfStatement": ">=1",
"IfStatementClosingBrace": ">=1",
"IfStatementOpeningBrace": ">=1",
"LogicalExpression": -1,
"MemberExpressionClosing": 0,
"MemberExpressionOpening": 0,
"MemberExpressionPeriod": 0,
"MethodDefinition": ">=1",
"ObjectExpressionOpeningBrace": "<=1",
"ObjectPatternClosingBrace": 0,
"ObjectPatternComma": 0,
"ObjectPatternOpeningBrace": 0,
"ParameterDefault": 0,
"Property": -1,
"PropertyName": 0,
"ReturnStatement": -1,
"SwitchCaseColon": ">=1",
"SwitchClosingBrace": ">=1",
"SwitchOpeningBrace": ">=1",
"ThisExpression": 0,
"ThrowStatement": ">=1",
"TryClosingBrace": 0,
"TryKeyword": -1,
"TryOpeningBrace": ">=1",
"VariableDeclaration": ">=1",
"VariableDeclarationSemiColon": ">=1",
"VariableValue": -1,
"WhileStatement": ">=1",
"WhileStatementClosingBrace": ">=1",
"WhileStatementOpeningBrace": ">=1"
}
},
"whiteSpace": {
"value": " ",
"removeTrailing": 1,
"before": {
"ArgumentComma": 0,
"ArgumentList": 0,
"ArgumentListArrayExpression": 0,
"ArgumentListFunctionExpression": 1,
"ArgumentListObjectExpression": 0,
"ArrayExpressionClosing": 0,
"ArrayExpressionComma": 0,
"ArrayExpressionOpening": 1,
"AssignmentOperator": 1,
"BinaryExpression": 0,
"BinaryExpressionOperator": 1,
"BlockComment": 1,
"CallExpression": 1,
"CatchClosingBrace": 1,
"CatchKeyword": 1,
"CatchOpeningBrace": 1,
"CatchParameterList": 0,
"CommaOperator": 0,
"ConditionalExpressionAlternate": 1,
"ConditionalExpressionConsequent": 1,
"DoWhileStatementClosingBrace": 1,
"DoWhileStatementConditional": 1,
"DoWhileStatementOpeningBrace": 1,
"ElseIfStatementClosingBrace": 1,
"ElseIfStatementOpeningBrace": 1,
"ElseStatementClosingBrace": 1,
"ElseStatementOpeningBrace": 1,
"EmptyStatement": 0,
"ExpressionClosingParentheses": 0,
"FinallyClosingBrace": 1,
"FinallyKeyword": -1,
"FinallyOpeningBrace": 1,
"ForInStatement": 1,
"ForInStatementClosingBrace": 1,
"ForInStatementExpressionClosing": 0,
"ForInStatementExpressionOpening": 1,
"ForInStatementOpeningBrace": 1,
"ForStatement": 1,
"ForStatementClosingBrace": 1,
"ForStatementExpressionClosing": 0,
"ForStatementExpressionOpening": 1,
"ForStatementOpeningBrace": 1,
"ForStatementSemicolon": 0,
"FunctionDeclarationClosingBrace": 1,
"FunctionDeclarationOpeningBrace": 1,
"FunctionExpressionClosingBrace": 1,
"FunctionExpressionOpeningBrace": 1,
"IfStatementClosingBrace": 1,
"IfStatementConditionalClosing": 0,
"IfStatementConditionalOpening": 1,
"IfStatementOpeningBrace": 1,
"LineComment": 1,
"LogicalExpressionOperator": 1,
"MemberExpressionClosing": 0,
"ObjectExpressionClosingBrace": 1,
"ParameterComma": 0,
"ParameterList": 0,
"Property": 1,
"PropertyName": 1,
"PropertyValue": 1,
"SwitchDiscriminantClosing": 0,
"SwitchDiscriminantOpening": 1,
"ThrowKeyword": 1,
"TryClosingBrace": 1,
"TryKeyword": -1,
"TryOpeningBrace": 1,
"UnaryExpressionOperator": 0,
"VariableName": 1,
"VariableValue": 1,
"WhileStatementClosingBrace": 1,
"WhileStatementConditionalClosing": 0,
"WhileStatementConditionalOpening": 1,
"WhileStatementOpeningBrace": 1
},
"after": {
"ArgumentComma": 1,
"ArgumentList": 0,
"ArgumentListArrayExpression": 1,
"ArgumentListFunctionExpression": 1,
"ArgumentListObjectExpression": 0,
"ArrayExpressionClosing": 0,
"ArrayExpressionComma": 1,
"ArrayExpressionOpening": 0,
"AssignmentOperator": 1,
"BinaryExpression": 0,
"BinaryExpressionOperator": 1,
"BlockComment": 1,
"CallExpression": 0,
"CatchClosingBrace": 1,
"CatchKeyword": 1,
"CatchOpeningBrace": 1,
"CatchParameterList": 0,
"CommaOperator": 1,
"ConditionalExpressionConsequent": 1,
"ConditionalExpressionTest": 1,
"DoWhileStatementBody": 1,
"DoWhileStatementClosingBrace": 1,
"DoWhileStatementOpeningBrace": 1,
"ElseIfStatementClosingBrace": 1,
"ElseIfStatementOpeningBrace": 1,
"ElseStatementClosingBrace": 1,
"ElseStatementOpeningBrace": 1,
"EmptyStatement": 0,
"ExpressionOpeningParentheses": 0,
"FinallyClosingBrace": 1,
"FinallyKeyword": -1,
"FinallyOpeningBrace": 1,
"ForInStatement": 1,
"ForInStatementClosingBrace": 1,
"ForInStatementExpressionClosing": 1,
"ForInStatementExpressionOpening": 0,
"ForInStatementOpeningBrace": 1,
"ForStatement": 1,
"ForStatementClosingBrace": 1,
"ForStatementExpressionClosing": 1,
"ForStatementExpressionOpening": 0,
"ForStatementOpeningBrace": 1,
"ForStatementSemicolon": 1,
"FunctionDeclarationClosingBrace": 0,
"FunctionDeclarationOpeningBrace": 0,
"FunctionExpressionClosingBrace": 0,
"FunctionExpressionOpeningBrace": 0,
"FunctionName": 0,
"FunctionReservedWord": 0,
"IfStatementClosingBrace": 1,
"IfStatementConditionalClosing": 0,
"IfStatementConditionalOpening": 0,
"IfStatementOpeningBrace": 1,
"LogicalExpressionOperator": 1,
"MemberExpressionOpening": 0,
"ObjectExpressionClosingBrace": 0,
"ObjectExpressionOpeningBrace": 1,
"ParameterComma": 1,
"ParameterList": 0,
"PropertyName": 0,
"PropertyValue": 0,
"SwitchDiscriminantClosing": 1,
"SwitchDiscriminantOpening": 0,
"ThrowKeyword": 1,
"TryClosingBrace": 1,
"TryKeyword": -1,
"TryOpeningBrace": 1,
"UnaryExpressionOperator": 0,
"VariableName": 1,
"WhileStatementClosingBrace": 1,
"WhileStatementConditionalClosing": 1,
"WhileStatementConditionalOpening": 0,
"WhileStatementOpeningBrace": 1
}
}
}

View File

@ -1,2 +1 @@
**/JsLibraries/**
**/*.css.d.ts

288
frontend/.eslintrc Normal file
View File

@ -0,0 +1,288 @@
{
"parser": "babel-eslint",
"env": {
"browser": true,
"commonjs": true,
"node": true,
"es6": true
},
"globals": {
"expect": false,
"chai": false,
"sinon": false
},
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"ecmaFeatures": {
"modules": true,
"impliedStrict": true
}
},
"plugins": [
"filenames",
"react"
],
"rules": {
"filenames/match-exported": ["error"],
# ECMAScript 6
"arrow-body-style": [0],
"arrow-parens": ["error", "always"],
"arrow-spacing": ["error", { "before": true, "after": true }],
"constructor-super": "error",
"generator-star-spacing": "off",
"no-class-assign": "error",
"no-confusing-arrow": "error",
"no-const-assign": "error",
"no-dupe-class-members": "error",
"no-duplicate-imports": "error",
"no-new-symbol": "error",
"no-this-before-super": "error",
"no-useless-escape": "error",
"no-useless-computed-key": "error",
"no-useless-constructor": "error",
"no-var": "warn",
"object-shorthand": ["error", "properties"],
"prefer-arrow-callback": "error",
"prefer-const": "warn",
"prefer-reflect": "off",
"prefer-rest-params": "off",
"prefer-spread": "warn",
"prefer-template": "error",
"require-yield": "off",
"template-curly-spacing": ["error", "never"],
"yield-star-spacing": "off",
# Possible Errors
"comma-dangle": "error",
"no-cond-assign": "error",
"no-console": "off",
"no-constant-condition": "warn",
"no-control-regex": "error",
"no-debugger": "off",
"no-dupe-args": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-empty": "warn",
"no-empty-character-class": "error",
"no-ex-assign": "error",
"no-extra-boolean-cast": "error",
"no-extra-parens": ["error", "functions"],
"no-extra-semi": "error",
"no-func-assign": "error",
"no-inner-declarations": "error",
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-negated-in-lhs": "error",
"no-obj-calls": "error",
"no-regex-spaces": "error",
"no-sparse-arrays": "error",
"no-unexpected-multiline": "error",
"no-unreachable": "warn",
"no-unsafe-finally": "error",
"use-isnan": "error",
"valid-jsdoc": "off",
"valid-typeof": "error",
# Best Practices
"accessor-pairs": "off",
"array-callback-return": "warn",
"block-scoped-var": "warn",
"consistent-return": "off",
"curly": "error",
"default-case": "error",
"dot-location": ["error", "property"],
"dot-notation": "error",
"eqeqeq": ["error", "smart"],
"guard-for-in": "error",
"no-alert": "warn",
"no-caller": "error",
"no-case-declarations": "error",
"no-div-regex": "error",
"no-else-return": "error",
"no-empty-function": ["error", {"allow": ["arrowFunctions"]}],
"no-empty-pattern": "error",
"no-eval": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-fallthrough": "error",
"no-floating-decimal": "error",
"no-implicit-coercion": ["error", {
"boolean": false,
"number": true,
"string": true,
"allow": [/* "!!", "~", "*", "+" */]
}],
"no-implicit-globals": "error",
"no-implied-eval": "error",
"no-invalid-this": "off",
"no-iterator": "error",
"no-labels": "error",
"no-lone-blocks": "error",
"no-loop-func": "error",
"no-magic-numbers": ["off", {"ignoreArrayIndexes": true, "ignore": [0, 1] }],
"no-multi-spaces": "error",
"no-multi-str": "error",
"no-native-reassign": ["error", {"exceptions": ["console"]}],
"no-new": "off",
"no-new-func": "error",
"no-new-wrappers": "error",
"no-octal": "error",
"no-octal-escape": "error",
"no-param-reassign": "off",
"no-process-env": "off",
"no-proto": "error",
"no-redeclare": "error",
"no-return-assign": "warn",
"no-script-url": "error",
"no-self-assign": "error",
"no-self-compare": "error",
"no-sequences": "error",
"no-throw-literal": "error",
"no-unmodified-loop-condition": "error",
"no-unused-expressions": "error",
"no-unused-labels": "error",
"no-useless-call": "error",
"no-useless-concat": "error",
"no-void": "error",
"no-warning-comments": "off",
"no-with": "error",
"radix": ["error", "as-needed"],
"vars-on-top": "off",
"wrap-iife": ["error", "inside"],
"yoda": "error",
# Strict Mode
"strict": ["error", "never"],
# Variables
"init-declarations": ["error", "always"],
"no-catch-shadow": "error",
"no-delete-var": "error",
"no-label-var": "error",
"no-restricted-globals": "off",
"no-shadow": "error",
"no-shadow-restricted-names": "error",
"no-undef": "error",
"no-undef-init": "off",
"no-undefined": "off",
"no-unused-vars": ["error", { "args": "none", "ignoreRestSiblings": true }],
"no-use-before-define": "error",
# Node.js and CommonJS
"callback-return": "warn",
"global-require": "error",
"handle-callback-err": "warn",
"no-mixed-requires": "error",
"no-new-require": "error",
"no-path-concat": "error",
"no-process-exit": "error",
# Stylistic Issues
"array-bracket-spacing": ["error", "never"],
"block-spacing": ["error", "always"],
"brace-style": ["error", "1tbs", { "allowSingleLine": false }],
"camelcase": "off",
"comma-spacing": ["error", {"before": false, "after": true}],
"comma-style": ["error", "last"],
"computed-property-spacing": ["error", "never"],
"consistent-this": ["error", "self"],
"eol-last": "error",
"func-names": "off",
"func-style": ["error", "declaration"],
"indent": ["error", 2, {"SwitchCase": 1}],
"key-spacing": ["error", {"beforeColon": false, "afterColon": true}],
"keyword-spacing": ["error", { "before": true, "after": true}],
"lines-around-comment": ["error", { "beforeBlockComment": true, "afterBlockComment": false }],
"max-depth": ["error", {"maximum": 5}],
"max-nested-callbacks": ["error", 4],
"max-params": ["error", 6],
"max-statements": "off",
"max-statements-per-line": ["error", { "max": 1 }],
"new-cap": ["error", {"capIsNewExceptions": ["$.Deferred", "DragDropContext", "DragLayer", "DragSource", "DropTarget"]}],
"new-parens": "error",
"newline-after-var": "off",
"newline-before-return": "off",
"newline-per-chained-call": "off",
"no-array-constructor": "error",
"no-bitwise": "error",
"no-continue": "error",
"no-inline-comments": "off",
"no-lonely-if": "warn",
"no-mixed-spaces-and-tabs": "error",
"no-multiple-empty-lines": ["error", { "max": 1 }],
"no-negated-condition": "warn",
"no-nested-ternary": "error",
"no-new-object": "error",
"no-plusplus": "off",
"no-restricted-syntax": "off",
"no-spaced-func": "error",
"no-ternary": "off",
"no-trailing-spaces": "error",
"no-underscore-dangle": ["error", { "allowAfterThis": true }],
"no-unneeded-ternary": "error",
"no-whitespace-before-property": "error",
"object-curly-spacing": ["error", "always"],
"one-var": ["error", "never"],
"one-var-declaration-per-line": ["error", "always"],
"operator-assignment": ["off", "never"],
"operator-linebreak": ["error", "after"],
"quote-props": ["error", "as-needed"],
"quotes": ["error", "single"],
"require-jsdoc": "off",
"semi": "error",
"semi-spacing": ["error", { "before": false, "after": true }],
"sort-vars": "off",
"space-before-blocks": ["error", "always"],
"space-before-function-paren": ["error", "never"],
"space-in-parens": "off",
"space-infix-ops": "off",
"space-unary-ops": "off",
"spaced-comment": "error",
"wrap-regex": "error",
# React
"react/jsx-boolean-value": [2, "always"],
"react/jsx-uses-vars": 2,
"react/jsx-closing-bracket-location": 2,
"react/jsx-tag-spacing": ["error"],
"react/jsx-curly-spacing": [2, "never"],
"react/jsx-equals-spacing": [2, "never"],
"react/jsx-indent-props": [2, 2],
"react/jsx-indent": [2, 2],
"react/jsx-key": 2,
"react/jsx-no-bind": [2, { "allowArrowFunctions": true }],
"react/jsx-no-duplicate-props": [2, { "ignoreCase": true }],
"react/jsx-max-props-per-line": [2, { "maximum": 2 }],
"react/jsx-handler-names": [2, { "eventHandlerPrefix": "(on|dispatch)", "eventHandlerPropPrefix": "on" }],
"react/jsx-no-undef": 2,
"react/jsx-pascal-case": 2,
"react/jsx-uses-react": 2,
// Explicitly disabled in case we want to enable them again
"react/no-did-mount-set-state": 0,
"react/no-did-update-set-state": 0,
"react/no-direct-mutation-state": 2,
"react/no-multi-comp": [2, { "ignoreStateless": true }],
"react/no-unknown-property": 2,
"react/prefer-es6-class": 2,
"react/prop-types": 2,
"react/react-in-jsx-scope": 2,
"react/self-closing-comp": 2,
"react/sort-comp": 2,
"react/jsx-wrap-multilines": 2
}
}

View File

@ -1,432 +0,0 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fs = require('fs');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const path = require('path');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const typescriptEslintRecommended = require('@typescript-eslint/eslint-plugin').configs.recommended;
const frontendFolder = __dirname;
const dirs = fs
.readdirSync(path.join(frontendFolder, 'src'), { withFileTypes: true })
.filter((dirent) => dirent.isDirectory())
.map((dirent) => dirent.name)
.join('|');
module.exports = {
root: true,
parser: '@babel/eslint-parser',
env: {
browser: true,
commonjs: true,
node: true,
es6: true
},
globals: {
expect: false,
chai: false,
sinon: false,
JSX: true
},
parserOptions: {
ecmaVersion: 6,
sourceType: 'module',
babelOptions: {
configFile: `${frontendFolder}/babel.config.js`
},
ecmaFeatures: {
modules: true,
impliedStrict: true
}
},
plugins: [
'filenames',
'react',
'react-hooks',
'simple-import-sort',
'import',
'@typescript-eslint',
'prettier'
],
settings: {
react: {
version: 'detect'
}
},
rules: {
'filenames/match-exported': ['error'],
// ECMAScript 6
'arrow-body-style': [0],
'arrow-parens': ['error', 'always'],
'arrow-spacing': ['error', { before: true, after: true }],
'constructor-super': 'error',
'generator-star-spacing': 'off',
'no-class-assign': 'error',
'no-confusing-arrow': 'error',
'no-const-assign': 'error',
'no-dupe-class-members': 'error',
'no-duplicate-imports': 'error',
'no-new-symbol': 'error',
'no-this-before-super': 'error',
'no-useless-escape': 'error',
'no-useless-computed-key': 'error',
'no-useless-constructor': 'error',
'no-var': 'warn',
'object-shorthand': ['error', 'properties'],
'prefer-arrow-callback': 'error',
'prefer-const': 'warn',
'prefer-reflect': 'off',
'prefer-rest-params': 'off',
'prefer-spread': 'warn',
'prefer-template': 'error',
'require-yield': 'off',
'template-curly-spacing': ['error', 'never'],
'yield-star-spacing': 'off',
// Possible Errors
'comma-dangle': 'error',
'no-cond-assign': 'error',
'no-console': 'off',
'no-constant-condition': 'warn',
'no-control-regex': 'error',
'no-debugger': 'off',
'no-dupe-args': 'error',
'no-dupe-keys': 'error',
'no-duplicate-case': 'error',
'no-empty': 'warn',
'no-empty-character-class': 'error',
'no-ex-assign': 'error',
'no-extra-boolean-cast': 'error',
'no-extra-parens': ['error', 'functions'],
'no-extra-semi': 'error',
'no-func-assign': 'error',
'no-inner-declarations': 'error',
'no-invalid-regexp': 'error',
'no-irregular-whitespace': 'error',
'no-negated-in-lhs': 'error',
'no-obj-calls': 'error',
'no-regex-spaces': 'error',
'no-sparse-arrays': 'error',
'no-unexpected-multiline': 'error',
'no-unreachable': 'warn',
'no-unsafe-finally': 'error',
'use-isnan': 'error',
'valid-jsdoc': 'off',
'valid-typeof': 'error',
// Best Practices
'accessor-pairs': 'off',
'array-callback-return': 'warn',
'block-scoped-var': 'warn',
'consistent-return': 'off',
curly: 'error',
'default-case': 'error',
'dot-location': ['error', 'property'],
'dot-notation': 'error',
eqeqeq: ['error', 'smart'],
'guard-for-in': 'error',
'no-alert': 'warn',
'no-caller': 'error',
'no-case-declarations': 'error',
'no-div-regex': 'error',
'no-else-return': 'error',
'no-empty-function': ['error', { allow: ['arrowFunctions'] }],
'no-empty-pattern': 'error',
'no-eval': 'error',
'no-extend-native': 'error',
'no-extra-bind': 'error',
'no-fallthrough': 'error',
'no-floating-decimal': 'error',
'no-implicit-coercion': ['error', {
boolean: false,
number: true,
string: true,
allow: [/* "!!", "~", "*", "+" */]
}],
'no-implicit-globals': 'error',
'no-implied-eval': 'error',
'no-invalid-this': 'off',
'no-iterator': 'error',
'no-labels': 'error',
'no-lone-blocks': 'error',
'no-loop-func': 'error',
'no-magic-numbers': ['off', { ignoreArrayIndexes: true, ignore: [0, 1] }],
'no-multi-spaces': 'error',
'no-multi-str': 'error',
'no-native-reassign': ['error', { exceptions: ['console'] }],
'no-new': 'off',
'no-new-func': 'error',
'no-new-wrappers': 'error',
'no-octal': 'error',
'no-octal-escape': 'error',
'no-param-reassign': 'off',
'no-process-env': 'off',
'no-proto': 'error',
'no-redeclare': 'error',
'no-return-assign': 'warn',
'no-script-url': 'error',
'no-self-assign': 'error',
'no-self-compare': 'error',
'no-sequences': 'error',
'no-throw-literal': 'error',
'no-unmodified-loop-condition': 'error',
'no-unused-expressions': 'error',
'no-unused-labels': 'error',
'no-useless-call': 'error',
'no-useless-concat': 'error',
'no-void': 'error',
'no-warning-comments': 'off',
'no-with': 'error',
radix: ['error', 'as-needed'],
'vars-on-top': 'off',
'wrap-iife': ['error', 'inside'],
yoda: 'error',
// Strict Mode
strict: ['error', 'never'],
// Variables
'init-declarations': ['error', 'always'],
'no-catch-shadow': 'error',
'no-delete-var': 'error',
'no-label-var': 'error',
'no-restricted-globals': 'off',
'no-shadow': 'error',
'no-shadow-restricted-names': 'error',
'no-undef': 'error',
'no-undef-init': 'off',
'no-undefined': 'off',
'no-unused-vars': ['error', { args: 'none', ignoreRestSiblings: true }],
'no-use-before-define': 'error',
// Node.js and CommonJS
'callback-return': 'warn',
'global-require': 'error',
'handle-callback-err': 'warn',
'no-mixed-requires': 'error',
'no-new-require': 'error',
'no-path-concat': 'error',
'no-process-exit': 'error',
// Stylistic Issues
'array-bracket-spacing': ['error', 'never'],
'block-spacing': ['error', 'always'],
'brace-style': ['error', '1tbs', { allowSingleLine: false }],
camelcase: 'off',
'comma-spacing': ['error', { before: false, after: true }],
'comma-style': ['error', 'last'],
'computed-property-spacing': ['error', 'never'],
'consistent-this': ['error', 'self'],
'eol-last': 'error',
'func-names': 'off',
'func-style': ['error', 'declaration', { allowArrowFunctions: true }],
indent: ['error', 2, { SwitchCase: 1 }],
'key-spacing': ['error', { beforeColon: false, afterColon: true }],
'keyword-spacing': ['error', { before: true, after: true }],
'lines-around-comment': ['error', { beforeBlockComment: true, afterBlockComment: false }],
'max-depth': ['error', { maximum: 5 }],
'max-nested-callbacks': ['error', 4],
'max-statements': 'off',
'max-statements-per-line': ['error', { max: 1 }],
'new-cap': ['error', { capIsNewExceptions: ['$.Deferred', 'DragDropContext', 'DragLayer', 'DragSource', 'DropTarget'] }],
'new-parens': 'error',
'newline-after-var': 'off',
'newline-before-return': 'off',
'newline-per-chained-call': 'off',
'no-array-constructor': 'error',
'no-bitwise': 'error',
'no-continue': 'error',
'no-inline-comments': 'off',
'no-lonely-if': 'warn',
'no-mixed-spaces-and-tabs': 'error',
'no-multiple-empty-lines': ['error', { max: 1 }],
'no-negated-condition': 'warn',
'no-nested-ternary': 'error',
'no-new-object': 'error',
'no-plusplus': 'off',
'no-restricted-syntax': 'off',
'no-spaced-func': 'error',
'no-ternary': 'off',
'no-trailing-spaces': 'error',
'no-underscore-dangle': ['error', { allowAfterThis: true }],
'no-unneeded-ternary': 'error',
'no-whitespace-before-property': 'error',
'object-curly-spacing': ['error', 'always'],
'one-var': ['error', 'never'],
'one-var-declaration-per-line': ['error', 'always'],
'operator-assignment': ['off', 'never'],
'operator-linebreak': ['error', 'after'],
'quote-props': ['error', 'as-needed'],
quotes: ['error', 'single'],
'require-jsdoc': 'off',
semi: 'error',
'semi-spacing': ['error', { before: false, after: true }],
'sort-vars': 'off',
'space-before-blocks': ['error', 'always'],
'space-before-function-paren': ['error', 'never'],
'space-in-parens': 'off',
'space-infix-ops': 'off',
'space-unary-ops': 'off',
'spaced-comment': 'error',
'wrap-regex': 'error',
// ImportSort
'simple-import-sort/imports': 'error',
'import/newline-after-import': 'error',
// React
'react/jsx-boolean-value': [2, 'always'],
'react/jsx-uses-vars': 2,
'react/jsx-closing-bracket-location': 2,
'react/jsx-tag-spacing': ['error'],
'react/jsx-curly-spacing': [2, 'never'],
'react/jsx-equals-spacing': [2, 'never'],
'react/jsx-indent-props': [2, 2],
'react/jsx-indent': [2, 2, { indentLogicalExpressions: true }],
'react/jsx-key': 2,
'react/jsx-no-bind': [2, { allowArrowFunctions: true }],
'react/jsx-no-duplicate-props': [2, { ignoreCase: true }],
'react/jsx-max-props-per-line': [2, { maximum: 2 }],
'react/jsx-handler-names': [2, { eventHandlerPrefix: '(on|dispatch)', eventHandlerPropPrefix: 'on' }],
'react/jsx-no-undef': 2,
'react/jsx-pascal-case': 2,
'react/jsx-uses-react': 2,
// Explicitly disabled in case we want to enable them again
'react/no-did-mount-set-state': 0,
'react/no-did-update-set-state': 0,
'react/no-direct-mutation-state': 2,
'react/no-multi-comp': [2, { ignoreStateless: true }],
'react/no-unknown-property': 2,
'react/prefer-es6-class': 2,
'react/prop-types': 2,
'react/react-in-jsx-scope': 2,
'react/self-closing-comp': 2,
'react/sort-comp': 2,
'react/jsx-wrap-multilines': 2,
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'error'
},
overrides: [
{
files: [
'*.js'
],
rules: {
'simple-import-sort/imports': [
'error',
{
groups: [
// Packages
// Absolute Paths
// Relative Paths
// Css
['^@?\\w', `^(${dirs})(/.*|$)`, '^\\.', '^\\..*css$']
]
}
]
}
},
{
files: [
'*.ts',
'*.tsx'
],
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json'
},
extends: [
'prettier'
],
rules: Object.assign(typescriptEslintRecommended.rules, {
'@typescript-eslint/no-unused-vars': [
'error',
{
args: 'after-used',
argsIgnorePattern: '^_',
ignoreRestSiblings: true
}
],
'@typescript-eslint/explicit-function-return-type': 'off',
'no-shadow': 'off',
'prettier/prettier': 'error',
'simple-import-sort/imports': [
'error',
{
groups: [
// Packages
// Absolute Paths
// Relative Paths
// Css
['^@?\\w', `^(${dirs})(/.*|$)`, '^\\.', '^\\..*css$']
]
}
],
// React Hooks
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'error',
// React
'react/function-component-definition': 'error',
'react/hook-use-state': 'error',
'react/jsx-boolean-value': ['error', 'always'],
'react/jsx-curly-brace-presence': [
'error',
{ props: 'never', children: 'never' }
],
'react/jsx-fragments': 'error',
'react/jsx-handler-names': [
'error',
{
eventHandlerPrefix: 'on',
eventHandlerPropPrefix: 'on'
}
],
'react/jsx-no-bind': ['error', { ignoreRefs: true }],
'react/jsx-no-useless-fragment': ['error', { allowExpressions: true }],
'react/jsx-pascal-case': ['error', { allowAllCaps: true }],
'react/jsx-sort-props': [
'error',
{
callbacksLast: true,
noSortAlphabetically: true,
reservedFirst: true
}
],
'react/prop-types': 'off',
'react/self-closing-comp': 'error'
})
},
{
files: [
'*.css.d.ts'
],
rules: {
'filenames/match-exported': 'off',
'init-declarations': 'off',
'prettier/prettier': 'off'
}
}
]
};

12
frontend/.jsbeautifyrc Normal file
View File

@ -0,0 +1,12 @@
{
"js": {
"indent_size": 2,
"indent_char": " ",
"indent_level": 2,
"indent_with_tabs": false,
"preserve_newlines": true,
"brace_style": "collapse",
"max_preserve_newlines": 2,
"jslint_happy": true
}
}

View File

@ -1,10 +0,0 @@
# Ignore everything recursively
*
# But not the .ts files
!*.ts*
*css.d.ts
# Check subdirectories too
!*/

View File

@ -1,6 +0,0 @@
{
"arrowParens": "always",
"endOfLine": "auto",
"singleQuote": true,
"trailingComma": "es5"
}

View File

@ -1,12 +1,12 @@
{
"plugins": [
"stylelint-order"
],
"ignoreFiles": [
"frontend/src/Styles/scaffolding.css",
"**/*.js"
],
"rules": {
"plugins": [
"stylelint-order"
],
"ignoreFiles": [
"frontend/src/Styles/scaffolding.css",
"**/*.js"
],
"rules": {
"at-rule-empty-line-before": [
"always",
{
@ -15,6 +15,9 @@
]
}
],
"at-rule-name-case": "lower",
"at-rule-name-newline-after": "always-multi-line",
"at-rule-name-space-after": "always",
"at-rule-no-unknown": [
true,
{
@ -25,36 +28,83 @@
}
],
"at-rule-no-vendor-prefix": true,
"at-rule-semicolon-newline-after": "always",
"at-rule-semicolon-space-before": "never",
"block-closing-brace-empty-line-before": "never",
"block-closing-brace-newline-after": "always",
"block-closing-brace-newline-before": "always",
"block-closing-brace-space-after": "always-single-line",
"block-closing-brace-space-before": "always-single-line",
"block-no-empty": true,
"block-opening-brace-newline-after": "always",
"block-opening-brace-newline-before": "never-single-line",
"block-opening-brace-space-after": "always-single-line",
"block-opening-brace-space-before": "always",
"color-hex-case": "lower",
"color-hex-length": "short",
"color-named": "never",
"color-no-invalid-hex": true,
"comment-whitespace-inside": "always",
"declaration-bang-space-after": "never",
"declaration-bang-space-before": "always",
"declaration-block-no-duplicate-properties": [
true,
{
"ignoreProperties": [
"composes"
"composes"
]
}
],
"declaration-block-no-redundant-longhand-properties": true,
"declaration-block-no-shorthand-property-overrides": true,
"declaration-block-semicolon-newline-after": "always",
"declaration-block-semicolon-newline-before": "never-multi-line",
"declaration-block-semicolon-space-before": "never",
"declaration-block-single-line-max-declarations": 1,
"declaration-block-trailing-semicolon": "always",
"declaration-colon-space-after": "always",
"declaration-colon-space-before": "never",
"font-family-name-quotes": "always-unless-keyword",
"function-calc-no-unspaced-operator": true,
"function-comma-newline-after": "never-multi-line",
"function-comma-newline-before": "never-multi-line",
"function-comma-space-after": "always",
"function-comma-space-before": "never",
"function-linear-gradient-no-nonstandard-direction": true,
"function-name-case": "lower",
"function-parentheses-newline-inside": "never-multi-line",
"function-parentheses-space-inside": "never",
"function-url-quotes": "always",
"function-url-scheme-disallowed-list": [
"function-url-scheme-blacklist": [
"data"
],
"function-whitespace-after": "always",
"indentation": 2,
"keyframe-declaration-no-important": true,
"length-zero-no-unit": true,
"max-empty-lines": 1,
"max-line-length": [
100,
{
"ignore": [
"non-comments"
]
}
],
"max-nesting-depth": 2,
"media-feature-colon-space-after": "always",
"media-feature-colon-space-before": "never",
"media-feature-name-case": "lower",
"media-feature-name-no-vendor-prefix": true,
"media-feature-range-operator-space-after": "always",
"media-feature-range-operator-space-before": "always",
"no-empty-source": true,
"no-eol-whitespace": true,
"no-extra-semicolons": true,
"no-invalid-double-slash-comments": true,
"no-missing-end-of-source-newline": true,
"number-leading-zero": "always",
"number-no-trailing-zeros": true,
"order/order": [
"custom-properties",
"dollar-variables",
@ -82,7 +132,6 @@
"right",
"bottom",
"left",
"inset",
"z-index",
"display",
"visibility",
@ -294,33 +343,54 @@
]
}
],
"property-case": "lower",
"property-no-vendor-prefix": true,
"rule-empty-line-before": [
"always",
{
"except": [
"first-nested"
"first-nested"
],
"ignore": [
"after-comment"
"after-comment"
]
}
],
"selector-attribute-brackets-space-inside": "never",
"selector-attribute-operator-space-after": "never",
"selector-attribute-operator-space-before": "never",
"selector-attribute-quotes": "never",
"selector-class-pattern": "^[A-Za-z0-9]+$",
"selector-combinator-space-after": "always",
"selector-combinator-space-before": "always",
"selector-descendant-combinator-no-non-space": true,
"selector-list-comma-newline-after": "always",
"selector-list-comma-newline-before": "never-multi-line",
"selector-list-comma-space-before": "never",
"selector-max-attribute": 0,
"selector-max-class": 3,
"selector-max-compound-selectors": 3,
"selector-max-empty-lines": 0,
"selector-max-id": 0,
"selector-max-universal": 0,
"selector-pseudo-class-case": "lower",
"selector-pseudo-class-parentheses-space-inside": "never",
"selector-pseudo-element-case": "lower",
"selector-pseudo-element-colon-notation": "double",
"selector-pseudo-element-no-unknown": true,
"selector-type-case": "lower",
"selector-type-no-unknown": true,
"shorthand-property-no-redundant-values": true,
"string-no-newline": true,
"string-quotes": "single",
"time-min-milliseconds": 100,
"unit-case": "lower",
"unit-no-unknown": true,
"value-list-comma-newline-after": "never-multi-line",
"value-list-comma-newline-before": "never-multi-line",
"value-list-comma-space-after": "always",
"value-list-comma-space-before": "never",
"value-list-max-empty-lines": 0,
"value-no-vendor-prefix": true
}
}

View File

@ -1,7 +0,0 @@
{
"recommendations": [
"stylelint.vscode-stylelint",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}

View File

@ -1,23 +0,0 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.insertFinalNewline": true,
"files.exclude": {
"**/node_modules": true,
"**/*.d.css": true
},
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll": true
},
"typescript.preferences.quoteStyle": "single",
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
}

View File

@ -1,39 +0,0 @@
const loose = true;
module.exports = {
plugins: [
'@babel/plugin-transform-logical-assignment-operators',
// Stage 1
'@babel/plugin-proposal-export-default-from',
['@babel/plugin-transform-optional-chaining', { loose }],
['@babel/plugin-transform-nullish-coalescing-operator', { loose }],
// Stage 2
'@babel/plugin-transform-export-namespace-from',
// Stage 3
['@babel/plugin-transform-class-properties', { loose }],
'@babel/plugin-syntax-dynamic-import'
],
env: {
development: {
presets: [
['@babel/preset-react', { development: true }],
'@babel/preset-typescript'
],
plugins: [
'babel-plugin-inline-classnames'
]
},
production: {
presets: [
'@babel/preset-react',
'@babel/preset-typescript'
],
plugins: [
'babel-plugin-transform-react-remove-prop-types'
]
}
}
};

View File

@ -1,284 +0,0 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path');
const webpack = require('webpack');
const FileManagerPlugin = require('filemanager-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const LiveReloadPlugin = require('webpack-livereload-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
module.exports = (env) => {
const uiFolder = 'UI';
const frontendFolder = path.join(__dirname, '..');
const srcFolder = path.join(frontendFolder, 'src');
const isProduction = !!env.production;
const isProfiling = isProduction && !!env.profile;
const inlineWebWorkers = 'no-fallback';
const distFolder = path.resolve(frontendFolder, '..', '_output', uiFolder);
console.log('Source Folder:', srcFolder);
console.log('Output Folder:', distFolder);
console.log('isProduction:', isProduction);
console.log('isProfiling:', isProfiling);
const config = {
mode: isProduction ? 'production' : 'development',
devtool: isProduction ? 'source-map' : 'eval-source-map',
stats: {
children: false
},
watchOptions: {
ignored: /node_modules/
},
entry: {
index: 'index.ts'
},
resolve: {
extensions: [
'.ts',
'.tsx',
'.js'
],
modules: [
srcFolder,
path.join(srcFolder, 'Shims'),
'node_modules'
],
alias: {
jquery: 'jquery/dist/jquery.min',
'react-middle-truncate': 'react-middle-truncate/lib/react-middle-truncate'
},
fallback: {
buffer: false,
http: false,
https: false,
url: false,
util: false,
net: false
}
},
output: {
path: distFolder,
publicPath: '/',
filename: isProduction ? '[name]-[contenthash].js' : '[name].js',
sourceMapFilename: '[file].map'
},
optimization: {
moduleIds: 'deterministic',
chunkIds: isProduction ? 'deterministic' : 'named'
},
performance: {
hints: false
},
experiments: {
topLevelAwait: true
},
plugins: [
new webpack.DefinePlugin({
__DEV__: !isProduction,
'process.env.NODE_ENV': isProduction ? JSON.stringify('production') : JSON.stringify('development')
}),
new MiniCssExtractPlugin({
filename: 'Content/styles.css',
chunkFilename: isProduction ? 'Content/[id]-[chunkhash].css' : 'Content/[id].css'
}),
new HtmlWebpackPlugin({
template: 'frontend/src/index.ejs',
filename: 'index.html',
publicPath: '/',
inject: false
}),
new FileManagerPlugin({
events: {
onEnd: {
copy: [
// HTML
{
source: 'frontend/src/*.html',
destination: distFolder
},
// Fonts
{
source: 'frontend/src/Content/Fonts/*.*',
destination: path.join(distFolder, 'Content/Fonts')
},
// Icon Images
{
source: 'frontend/src/Content/Images/Icons/*.*',
destination: path.join(distFolder, 'Content/Images/Icons')
},
// Images
{
source: 'frontend/src/Content/Images/*.*',
destination: path.join(distFolder, 'Content/Images')
},
// Robots
{
source: 'frontend/src/Content/robots.txt',
destination: path.join(distFolder, 'Content/robots.txt')
}
]
}
}
}),
new ForkTsCheckerWebpackPlugin(),
new LiveReloadPlugin()
],
resolveLoader: {
modules: [
'node_modules',
'frontend/build/webpack/'
]
},
module: {
rules: [
{
test: /\.worker\.js$/,
use: {
loader: 'worker-loader',
options: {
filename: '[name].js',
inline: inlineWebWorkers
}
}
},
{
test: [/\.jsx?$/, /\.tsx?$/],
exclude: /(node_modules|JsLibraries)/,
use: [
{
loader: 'babel-loader',
options: {
configFile: `${frontendFolder}/babel.config.js`,
envName: isProduction ? 'production' : 'development',
presets: [
[
'@babel/preset-env',
{
modules: false,
loose: true,
debug: false,
useBuiltIns: 'entry',
corejs: 3
}
]
]
}
}
]
},
// CSS Modules
{
test: /\.css$/,
exclude: /(node_modules|globals.css)/,
use: [
{ loader: MiniCssExtractPlugin.loader },
{ loader: 'css-modules-typescript-loader' },
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: {
localIdentName: isProduction ? '[name]/[local]/[hash:base64:5]' : '[name]/[local]'
}
}
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
config: 'frontend/postcss.config.js'
}
}
}
]
},
// Global styles
{
test: /\.css$/,
include: /(node_modules|globals.css)/,
use: [
'style-loader',
{
loader: 'css-loader'
}
]
},
// Fonts
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10240,
mimetype: 'application/font-woff',
emitFile: false,
name: 'Content/Fonts/[name].[ext]'
}
}
]
},
{
test: /\.(ttf|eot|eot?#iefix|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [
{
loader: 'file-loader',
options: {
emitFile: false,
name: 'Content/Fonts/[name].[ext]'
}
}
]
}
]
}
};
if (isProfiling) {
config.resolve.alias['react-dom$'] = 'react-dom/profiling';
config.resolve.alias['scheduler/tracing'] = 'scheduler/tracing-profiling';
config.optimization = {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
sourceMap: true, // Must be set to true if using source-maps in production
mangle: false,
keep_classnames: true,
keep_fnames: true
}
})
]
};
}
return config;
};

15
frontend/gulp/build.js Normal file
View File

@ -0,0 +1,15 @@
const gulp = require('gulp');
const runSequence = require('run-sequence');
require('./clean');
require('./copy');
gulp.task('build', () => {
return runSequence('clean', [
'webpack',
'copyHtml',
'copyFonts',
'copyImages',
'copyJs'
]);
});

8
frontend/gulp/clean.js Normal file
View File

@ -0,0 +1,8 @@
const gulp = require('gulp');
const del = require('del');
const paths = require('./helpers/paths');
gulp.task('clean', () => {
return del([paths.dest.root]);
});

45
frontend/gulp/copy.js Normal file
View File

@ -0,0 +1,45 @@
var path = require('path');
var gulp = require('gulp');
var print = require('gulp-print').default;
var cache = require('gulp-cached');
var livereload = require('gulp-livereload');
var paths = require('./helpers/paths.js');
gulp.task('copyJs', () => {
return gulp.src(
[
path.join(paths.src.root, 'polyfills.js')
])
.pipe(cache('copyJs'))
.pipe(print())
.pipe(gulp.dest(paths.dest.root))
.pipe(livereload());
});
gulp.task('copyHtml', () => {
return gulp.src(paths.src.html)
.pipe(cache('copyHtml'))
.pipe(print())
.pipe(gulp.dest(paths.dest.root))
.pipe(livereload());
});
gulp.task('copyFonts', () => {
return gulp.src(
path.join(paths.src.fonts, '**', '*.*')
)
.pipe(cache('copyFonts'))
.pipe(print())
.pipe(gulp.dest(paths.dest.fonts))
.pipe(livereload());
});
gulp.task('copyImages', () => {
return gulp.src(
path.join(paths.src.images, '**', '*.*')
)
.pipe(cache('copyImages'))
.pipe(print())
.pipe(gulp.dest(paths.dest.images))
.pipe(livereload());
});

View File

@ -0,0 +1,8 @@
require('./build.js');
require('./clean.js');
require('./copy.js');
require('./imageMin.js');
require('./start.js');
require('./stripBom.js');
require('./watch.js');
require('./webpack.js');

View File

@ -0,0 +1,6 @@
const gulpUtil = require('gulp-util');
module.exports = function errorHandler(error) {
gulpUtil.log(gulpUtil.colors.red(`Error (${error.plugin}): ${error.message}`));
this.emit('end');
};

View File

@ -0,0 +1,15 @@
const path = require('path');
const rootPath = path.resolve(__dirname + '/../../src/');
module.exports = function(source) {
if (this.cacheable) {
this.cacheable();
}
const resourcePath = this.resourcePath.replace(rootPath, '');
const wrappedSource =`
<!-- begin ${resourcePath} -->
${source}
<!-- end ${resourcePath} -->`;
return wrappedSource;
};

View File

@ -0,0 +1,23 @@
const root = './frontend/src/';
const paths = {
src: {
root,
html: root + '*.html',
scripts: root + '**/*.js',
content: root + 'Content/',
fonts: root + 'Content/Fonts/',
images: root + 'Content/Images/',
exclude: {
libs: `!${root}JsLibraries/**`
}
},
dest: {
root: './_output/UI/',
content: './_output/UI/Content/',
fonts: './_output/UI/Content/Fonts/',
images: './_output/UI/Content/Images/'
}
};
module.exports = paths;

15
frontend/gulp/imageMin.js Normal file
View File

@ -0,0 +1,15 @@
var gulp = require('gulp');
var print = require('gulp-print').default;
var paths = require('./helpers/paths.js');
gulp.task('imageMin', () => {
var imagemin = require('gulp-imagemin');
return gulp.src(paths.src.images)
.pipe(imagemin({
progressive: false,
optimizationLevel: 4,
svgoPlugins: [{ removeViewBox: false }]
}))
.pipe(print())
.pipe(gulp.dest(paths.src.content + 'Images/'));
});

104
frontend/gulp/start.js Normal file
View File

@ -0,0 +1,104 @@
// will download and run sonarr (server) in a non-windows enviroment
// you can use this if you don't care about the server code and just want to work
// with the web code.
var http = require('http');
var gulp = require('gulp');
var fs = require('fs');
var targz = require('tar.gz');
var del = require('del');
var spawn = require('child_process').spawn;
function download(url, dest, cb) {
console.log('Downloading ' + url + ' to ' + dest);
var file = fs.createWriteStream(dest);
http.get(url, function(response) {
response.pipe(file);
file.on('finish', function() {
console.log('Download completed');
file.close(cb);
});
});
}
function getLatest(cb) {
var branch = 'develop';
process.argv.forEach(function(val) {
var branchMatch = /branch=([\S]*)/.exec(val);
if (branchMatch && branchMatch.length > 1) {
branch = branchMatch[1];
}
});
var url = 'http://services.sonarr.tv/v1/update/' + branch + '?os=osx';
console.log('Checking for latest version:', url);
http.get(url, function(res) {
var data = '';
res.on('data', function(chunk) {
data += chunk;
});
res.on('end', function() {
var updatePackage = JSON.parse(data).updatePackage;
console.log('Latest version available: ' + updatePackage.version + ' Release Date: ' + updatePackage.releaseDate);
cb(updatePackage);
});
}).on('error', function(e) {
console.log('problem with request: ' + e.message);
});
}
function extract(source, dest, cb) {
console.log('extracting download page to ' + dest);
new targz().extract(source, dest, function(err) {
if (err) {
console.log(err);
}
console.log('Update package extracted.');
cb();
});
}
gulp.task('getSonarr', function() {
try {
fs.mkdirSync('./_start/');
} catch (e) {
if (e.code !== 'EEXIST') {
throw e;
}
}
getLatest(function(updatePackage) {
var packagePath = './_start/' + updatePackage.filename;
var dirName = './_start/' + updatePackage.version;
download(updatePackage.url, packagePath, function() {
extract(packagePath, dirName, function() {
// clean old binaries
console.log('Cleaning old binaries');
del.sync(['./_output/*', '!./_output/UI/']);
console.log('copying binaries to target');
gulp.src(dirName + '/NzbDrone/*.*')
.pipe(gulp.dest('./_output/'));
});
});
});
});
gulp.task('startSonarr', function() {
var ls = spawn('mono', ['--debug', './_output/NzbDrone.exe']);
ls.stdout.on('data', function(data) {
process.stdout.write(data);
});
ls.stderr.on('data', function(data) {
process.stdout.write(data);
});
ls.on('close', function(code) {
console.log('child process exited with code ' + code);
});
});

13
frontend/gulp/stripBom.js Normal file
View File

@ -0,0 +1,13 @@
const gulp = require('gulp');
const paths = require('./helpers/paths.js');
const stripbom = require('gulp-stripbom');
function stripBom(dest) {
gulp.src([paths.src.scripts, paths.src.exclude.libs])
.pipe(stripbom({ showLog: false }))
.pipe(gulp.dest(dest));
}
gulp.task('stripBom', () => {
stripBom(paths.src.root);
});

27
frontend/gulp/watch.js Normal file
View File

@ -0,0 +1,27 @@
const gulp = require('gulp');
const livereload = require('gulp-livereload');
const watch = require('gulp-watch');
const paths = require('./helpers/paths.js');
require('./copy.js');
require('./webpack.js');
function watchTask(glob, task) {
const options = {
name: `watch: ${task}`,
verbose: true
};
return watch(glob, options, () => {
gulp.start(task);
});
}
gulp.task('watch', ['copyHtml', 'copyFonts', 'copyImages', 'copyJs'], () => {
livereload.listen({ start: true });
gulp.start('webpackWatch');
watchTask(paths.src.html, 'copyHtml');
watchTask(`${paths.src.fonts}**/*.*`, 'copyFonts');
watchTask(`${paths.src.images}**/*.*`, 'copyImages');
});

212
frontend/gulp/webpack.js Normal file
View File

@ -0,0 +1,212 @@
const gulp = require('gulp');
const webpackStream = require('webpack-stream');
const livereload = require('gulp-livereload');
const path = require('path');
const webpack = require('webpack');
const errorHandler = require('./helpers/errorHandler');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const uiFolder = 'UI';
const root = path.join(__dirname, '..', 'src');
const isProduction = process.argv.indexOf('--production') > -1;
console.log('ROOT:', root);
console.log('isProduction:', isProduction);
const cssVarsFiles = [
'../src/Styles/Variables/colors',
'../src/Styles/Variables/dimensions',
'../src/Styles/Variables/fonts',
'../src/Styles/Variables/animations'
].map(require.resolve);
const extractCSSPlugin = new ExtractTextPlugin({
filename: path.join('_output', uiFolder, 'Content', 'styles.css'),
allChunks: true,
disable: false,
ignoreOrder: true
});
const plugins = [
extractCSSPlugin,
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor'
}),
new webpack.DefinePlugin({
__DEV__: !isProduction,
'process.env.NODE_ENV': isProduction ? JSON.stringify('production') : JSON.stringify('development')
})
];
if (isProduction) {
plugins.push(new UglifyJSPlugin({
sourceMap: true,
uglifyOptions: {
mangle: false,
output: {
comments: false,
beautify: true
}
}
}));
}
const config = {
devtool: '#source-map',
stats: {
children: false
},
watchOptions: {
ignored: /node_modules/
},
entry: {
preload: 'preload.js',
vendor: 'vendor.js',
index: 'index.js'
},
resolve: {
modules: [
root,
path.join(root, 'Shims'),
'node_modules'
],
alias: {
jquery: 'jquery/src/jquery'
}
},
output: {
filename: path.join('_output', uiFolder, '[name].js'),
sourceMapFilename: '[file].map'
},
plugins,
resolveLoader: {
modules: [
'node_modules',
'frontend/gulp/webpack/'
]
},
module: {
rules: [
{
test: /\.js?$/,
exclude: /(node_modules|JsLibraries)/,
loader: 'babel-loader',
query: {
plugins: ['transform-class-properties'],
presets: ['es2015', 'decorators-legacy', 'react', 'stage-2'],
env: {
development: {
plugins: ['transform-react-jsx-source']
}
}
}
},
// CSS Modules
{
test: /\.css$/,
exclude: /(node_modules|globals.css)/,
use: extractCSSPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-variables-loader',
options: {
cssVarsFiles
}
},
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1,
localIdentName: '[name]-[local]-[hash:base64:5]',
sourceMap: true
}
},
{
loader: 'postcss-loader',
options: {
config: {
ctx: {
cssVarsFiles
},
path: 'frontend/postcss.config.js'
}
}
}
]
})
},
// Global styles
{
test: /\.css$/,
include: /(node_modules|globals.css)/,
use: [
'style-loader',
{
loader: 'css-loader'
}
]
},
// Fonts
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10240,
mimetype: 'application/font-woff',
emitFile: false,
name: 'Content/Fonts/[name].[ext]'
}
}
]
},
{
test: /\.(ttf|eot|eot?#iefix|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [
{
loader: 'file-loader',
options: {
emitFile: false,
name: 'Content/Fonts/[name].[ext]'
}
}
]
}
]
}
};
gulp.task('webpack', () => {
return gulp.src('index.js')
.pipe(webpackStream(config))
.pipe(gulp.dest(''));
});
gulp.task('webpackWatch', () => {
config.watch = true;
return gulp.src('')
.pipe(webpackStream(config))
.on('error', errorHandler)
.pipe(gulp.dest(''))
.on('error', errorHandler)
.pipe(livereload())
.on('error', errorHandler);
});

View File

@ -1,4 +1,3 @@
// eslint-disable-next-line filenames/match-exported
const loaderUtils = require('loader-utils');
module.exports = function cssVariablesLoader(source) {

View File

@ -1,31 +1,33 @@
const reload = require('require-nocache')(module);
const cssVarsFiles = [
'./src/Styles/Variables/dimensions',
'./src/Styles/Variables/fonts',
'./src/Styles/Variables/animations',
'./src/Styles/Variables/zIndexes'
].map(require.resolve);
module.exports = (ctx, configPath, options) => {
const config = {
plugins: {
'postcss-mixins': {
mixinsDir: [
'frontend/src/Styles/Mixins'
]
},
'postcss-simple-vars': {
variables: () =>
ctx.options.cssVarsFiles.reduce((acc, vars) => {
return Object.assign(acc, reload(vars));
}, {})
},
'postcss-nested': {},
autoprefixer: {
browsers: [
'Chrome >= 30',
'Firefox >= 30',
'Safari >= 6',
'Edge >= 12',
'Explorer >= 11',
'iOS >= 7',
'Android >= 4.4'
]
}
}
};
const mixinsFiles = [
'frontend/src/Styles/Mixins/cover.css',
'frontend/src/Styles/Mixins/linkOverlay.css',
'frontend/src/Styles/Mixins/scroller.css',
'frontend/src/Styles/Mixins/truncate.css'
];
module.exports = {
plugins: [
['postcss-mixins', {
mixinsFiles
}],
['postcss-simple-vars', {
variables: () =>
cssVarsFiles.reduce((acc, vars) => {
return Object.assign(acc, reload(vars));
}, {})
}],
'postcss-color-function',
'postcss-nested'
]
return config;
};

4
frontend/src/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,4 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.insertFinalNewline": true
}

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