Compare commits
400 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b72a12540 | ||
|
|
38a1b7765a | ||
|
|
02f2b8b6f0 | ||
|
|
7bfa75102c | ||
|
|
b0f3e7351c | ||
|
|
b5fa401db9 | ||
|
|
41f2710dea | ||
|
|
f19dda57f0 | ||
|
|
cc4a99ad80 | ||
|
|
1c1a3fc417 | ||
|
|
e97be5850b | ||
|
|
2c302654b7 | ||
|
|
3ee4dc77b2 | ||
|
|
db55f314c9 | ||
|
|
0b536b287f | ||
|
|
6f298a9917 | ||
|
|
70f829a2e5 | ||
|
|
1dfe07003f | ||
|
|
286b908062 | ||
|
|
4ec028e736 | ||
|
|
35a6d1437a | ||
|
|
7e3cb3de89 | ||
|
|
bd945039f1 | ||
|
|
46743c8f15 | ||
|
|
9b75284447 | ||
|
|
dca3b0052a | ||
|
|
6d05bb2de5 | ||
|
|
8b2e8d3804 | ||
|
|
1a2ab19ab4 | ||
|
|
04f010aa7b | ||
|
|
25323b4a3a | ||
|
|
f353c022f6 | ||
|
|
9d8b3d3428 | ||
|
|
e4b06772c0 | ||
|
|
a2b5c3ea08 | ||
|
|
f632e95600 | ||
|
|
4b5da8c6d4 | ||
|
|
77d7ffd10a | ||
|
|
d2f720011a | ||
|
|
6329a7711d | ||
|
|
fd14d044e3 | ||
|
|
6368d507e1 | ||
|
|
205b7f2401 | ||
|
|
f7d10f9530 | ||
|
|
66154bb51e | ||
|
|
fac4ad5313 | ||
|
|
fee63891ac | ||
|
|
efa979ee03 | ||
|
|
c756346357 | ||
|
|
cc95db25cc | ||
|
|
44970c3321 | ||
|
|
43c7934af7 | ||
|
|
3e7b51163c | ||
|
|
4d5f8a53f0 | ||
|
|
0b73ca8318 | ||
|
|
754cfc3bfd | ||
|
|
2ed1a5c06a | ||
|
|
b2073df3c3 | ||
|
|
6267edaa81 | ||
|
|
292f2de3e6 | ||
|
|
7803dc8be3 | ||
|
|
2a1260b79e | ||
|
|
f9ec438b7f | ||
|
|
de544c4856 | ||
|
|
55e04dd520 | ||
|
|
b2d06f900b | ||
|
|
b92ec71810 | ||
|
|
3a4199240e | ||
|
|
157de12bdf | ||
|
|
7c0c9fccdb | ||
|
|
2cb29d06b3 | ||
|
|
1fdeb50d93 | ||
|
|
f59632ae59 | ||
|
|
67b503da44 | ||
|
|
a351de6904 | ||
|
|
f94742abd5 | ||
|
|
891182637e | ||
|
|
086681c915 | ||
|
|
3970d2d02b | ||
|
|
2b3fddd015 | ||
|
|
30fa0480a3 | ||
|
|
320a81ce69 | ||
|
|
950411ef56 | ||
|
|
cb9cf084c0 | ||
|
|
bb18af09ae | ||
|
|
049bf0c7f9 | ||
|
|
ebc73ef775 | ||
|
|
1bd6f59355 | ||
|
|
c16396a690 | ||
|
|
32a9fe3e9c | ||
|
|
f48d133bc6 | ||
|
|
0678526d7d | ||
|
|
26d3e8371f | ||
|
|
6768f614c7 | ||
|
|
171dc84df1 | ||
|
|
5ca6513c04 | ||
|
|
41aeb0ac80 | ||
|
|
f871c4adef | ||
|
|
ad4d0e89b1 | ||
|
|
0d0c49caa1 | ||
|
|
7cbc7bdcfb | ||
|
|
6b46c8ed4a | ||
|
|
e33ffd1c8a | ||
|
|
8dce9cc938 | ||
|
|
f06218f8e3 | ||
|
|
5711eef2be | ||
|
|
db6aac603c | ||
|
|
f10e928106 | ||
|
|
99d963b99c | ||
|
|
5d35c22238 | ||
|
|
54fc11a235 | ||
|
|
ec99df3144 | ||
|
|
d722035883 | ||
|
|
52139fbaa0 | ||
|
|
88854eb558 | ||
|
|
c82bba01ee | ||
|
|
eaa33a03d7 | ||
|
|
89e8518f31 | ||
|
|
c7bf2e1da8 | ||
|
|
bf904a6afa | ||
|
|
43c14ae71b | ||
|
|
4abb8ef3c9 | ||
|
|
e46b92dd7d | ||
|
|
1a25faa5b9 | ||
|
|
3f4bf5f512 | ||
|
|
ae7dbf15ed | ||
|
|
b22320c48f | ||
|
|
61204e8d35 | ||
|
|
b0704c654c | ||
|
|
f40f8a8873 | ||
|
|
560a7db506 | ||
|
|
15baa8f70e | ||
|
|
97a7637294 | ||
|
|
3454656207 | ||
|
|
7dff6f26bc | ||
|
|
9e835a23fd | ||
|
|
c0259fb6ce | ||
|
|
acf106220b | ||
|
|
5d4dc9c907 | ||
|
|
2b9a56af7f | ||
|
|
f1e3ac65ac | ||
|
|
143f72cf6b | ||
|
|
5c8e49296c | ||
|
|
b2558b703c | ||
|
|
bf9d87106e | ||
|
|
5b7f507d9b | ||
|
|
59a7835ace | ||
|
|
2495838fe3 | ||
|
|
bab687bedf | ||
|
|
6467c3c8ee | ||
|
|
66c2b7aaa6 | ||
|
|
ab72c52661 | ||
|
|
f0bf1b8a54 | ||
|
|
119251719f | ||
|
|
0348400132 | ||
|
|
813473805b | ||
|
|
fe6368561b | ||
|
|
7ff06f424d | ||
|
|
31958592c7 | ||
|
|
adc21f4f75 | ||
|
|
9cecd89d6f | ||
|
|
d866b9b4d4 | ||
|
|
93f12baf51 | ||
|
|
78d6fd634b | ||
|
|
b5fc19f08a | ||
|
|
2dae6a6546 | ||
|
|
b6bba46391 | ||
|
|
b791d97116 | ||
|
|
6aa8255f34 | ||
|
|
98e2140761 | ||
|
|
a59e064778 | ||
|
|
655c4c66a7 | ||
|
|
407c128f65 | ||
|
|
59a261a5be | ||
|
|
ba4e1afefe | ||
|
|
98b53b81d8 | ||
|
|
8270cc0aa2 | ||
|
|
74207b1a87 | ||
|
|
77983445ce | ||
|
|
162190bcb8 | ||
|
|
86b92b20b7 | ||
|
|
2f5b60d548 | ||
|
|
c19661c977 | ||
|
|
82d101ca27 | ||
|
|
32f9c4e670 | ||
|
|
34c7225ab7 | ||
|
|
b02eb502e4 | ||
|
|
7d6b3dfd20 | ||
|
|
3ac39968d2 | ||
|
|
2b24ac54a0 | ||
|
|
6da6b794c7 | ||
|
|
ed689e27c9 | ||
|
|
186f9c3f18 | ||
|
|
42cdde3203 | ||
|
|
b9091702e9 | ||
|
|
d42ecbe74e | ||
|
|
e6c5446d63 | ||
|
|
cc277211b3 | ||
|
|
6703c15c52 | ||
|
|
4ecdaf573e | ||
|
|
71ec3e61be | ||
|
|
216fdb2393 | ||
|
|
c39acc6e3c | ||
|
|
d97b0478a7 | ||
|
|
d15d64eb67 | ||
|
|
3acd2656ee | ||
|
|
a4b003534a | ||
|
|
8752538a02 | ||
|
|
bde435753a | ||
|
|
d347e6fc5f | ||
|
|
27b01d3642 | ||
|
|
b78677e285 | ||
|
|
f8f6c74bcb | ||
|
|
7ce123939b | ||
|
|
e7b02cfb15 | ||
|
|
5931077b08 | ||
|
|
a521bdc0e3 | ||
|
|
80da565609 | ||
|
|
6bc46e4598 | ||
|
|
6562258db5 | ||
|
|
c219995218 | ||
|
|
62035431ed | ||
|
|
fa1fbca7dc | ||
|
|
391b7476b3 | ||
|
|
9c04ce665f | ||
|
|
dd87268197 | ||
|
|
8d9af59db2 | ||
|
|
1b754a35ff | ||
|
|
7230f91f61 | ||
|
|
93edfc315c | ||
|
|
74c8269531 | ||
|
|
acb6c0fc83 | ||
|
|
553d4cce93 | ||
|
|
ca81f144e6 | ||
|
|
ec84960347 | ||
|
|
38db0764af | ||
|
|
a647f63bb0 | ||
|
|
5b7087cc9e | ||
|
|
1a6fcd5da6 | ||
|
|
e31dd9f553 | ||
|
|
22844716d1 | ||
|
|
6abed76f70 | ||
|
|
72ff502e0f | ||
|
|
2b781df32b | ||
|
|
bf601c3906 | ||
|
|
b753e0ebb0 | ||
|
|
564211aceb | ||
|
|
538c759fef | ||
|
|
95edc34100 | ||
|
|
98682a2da9 | ||
|
|
33581fa61d | ||
|
|
b02e0aae98 | ||
|
|
6fa4e1cb6d | ||
|
|
9f2ec22e95 | ||
|
|
65b2e506b1 | ||
|
|
8bc07b5286 | ||
|
|
fe0af63795 | ||
|
|
44ce7f4c67 | ||
|
|
252936134b | ||
|
|
e255b06945 | ||
|
|
d726568a23 | ||
|
|
66880a6de7 | ||
|
|
fda622a0c0 | ||
|
|
efa7d10f40 | ||
|
|
348a3fabab | ||
|
|
1bbaee605c | ||
|
|
22edf7a2b3 | ||
|
|
3ffcc29249 | ||
|
|
21f1fe52c0 | ||
|
|
99840c9e4f | ||
|
|
3194fe7d8e | ||
|
|
81df72b0cb | ||
|
|
57b056ac43 | ||
|
|
c5876d0d48 | ||
|
|
b5e65401b6 | ||
|
|
ebea5b48ea | ||
|
|
7d081e581a | ||
|
|
5e819cf04b | ||
|
|
fd9ab43681 | ||
|
|
4935cdc722 | ||
|
|
26a3c7ad6a | ||
|
|
c358216ad9 | ||
|
|
bb9302143c | ||
|
|
3a73553aac | ||
|
|
6447a17e3e | ||
|
|
4bd5c8ffb3 | ||
|
|
89f137b211 | ||
|
|
3425572c66 | ||
|
|
ad50875f9c | ||
|
|
34e5645dab | ||
|
|
e8ae91c230 | ||
|
|
44b83994fa | ||
|
|
201f585350 | ||
|
|
e4d2f1925e | ||
|
|
658c116eac | ||
|
|
dbbedee77f | ||
|
|
16ac9ea061 | ||
|
|
6afbc71b4a | ||
|
|
71263863ad | ||
|
|
05232065f8 | ||
|
|
f289ae4143 | ||
|
|
91703ecec4 | ||
|
|
6fb0858b87 | ||
|
|
f1c6620df9 | ||
|
|
08fed9a5ee | ||
|
|
eb28b3b05b | ||
|
|
f0c354b0c9 | ||
|
|
07d88e86a2 | ||
|
|
f41a3b9bb2 | ||
|
|
bfd9e76f40 | ||
|
|
38ce208a43 | ||
|
|
fcd148b8d5 | ||
|
|
fc6c3774b0 | ||
|
|
18023d2e18 | ||
|
|
467e834ad6 | ||
|
|
629d9e7ae0 | ||
|
|
4487d292e8 | ||
|
|
76711b9a66 | ||
|
|
b54c749e43 | ||
|
|
d82fd421ed | ||
|
|
abdcadb5fa | ||
|
|
fa3891e383 | ||
|
|
f1dc0f95c8 | ||
|
|
5c721d243a | ||
|
|
2770384f1f | ||
|
|
f4e5b83039 | ||
|
|
124681605b | ||
|
|
a217faae7c | ||
|
|
184c39bbb7 | ||
|
|
508e2a70bb | ||
|
|
5aac56fe96 | ||
|
|
dab7dad966 | ||
|
|
25e48d6cae | ||
|
|
9b743e55d1 | ||
|
|
dc1f9edfaf | ||
|
|
b6b68edf1e | ||
|
|
a2320b99ae | ||
|
|
be01e28068 | ||
|
|
d6084083a5 | ||
|
|
019bf5102c | ||
|
|
a1633224d1 | ||
|
|
e62bd26cb9 | ||
|
|
c29f517292 | ||
|
|
d80144f80c | ||
|
|
4733c84a86 | ||
|
|
23f3d2095b | ||
|
|
4f1f2b6fc6 | ||
|
|
1ea70b085f | ||
|
|
6c0b395f4a | ||
|
|
0ee67f186f | ||
|
|
d133addbaa | ||
|
|
683991b1c9 | ||
|
|
32ac02007b | ||
|
|
d716617ae0 | ||
|
|
26e1f015d2 | ||
|
|
1c94093a4b | ||
|
|
27eccd456a | ||
|
|
eed4447560 | ||
|
|
3c8d0ebd52 | ||
|
|
7ec0d2f2cc | ||
|
|
35da91a997 | ||
|
|
788747c071 | ||
|
|
36eb131289 | ||
|
|
f231f28818 | ||
|
|
aebdc89f77 | ||
|
|
4a3a379871 | ||
|
|
a7f27add2d | ||
|
|
cd1d4247cf | ||
|
|
6d618c4b78 | ||
|
|
ad469531ff | ||
|
|
cf9b4b1246 | ||
|
|
18a2692dc1 | ||
|
|
a2dad982f8 | ||
|
|
8f27b6a4c9 | ||
|
|
21c4022fca | ||
|
|
237933855a | ||
|
|
dff7068a03 | ||
|
|
8f28a85a6d | ||
|
|
2414eb2598 | ||
|
|
4851f6bffd | ||
|
|
948be36d3c | ||
|
|
edd088927d | ||
|
|
4cfe8dd95e | ||
|
|
e1ce81c5bf | ||
|
|
0f40b5f022 | ||
|
|
94c5ffa92e | ||
|
|
3c9bf56767 | ||
|
|
9024acb16e | ||
|
|
7732402122 | ||
|
|
2059bce6a7 | ||
|
|
499c86a8b8 | ||
|
|
ef084eb145 | ||
|
|
3f3ae7c38f | ||
|
|
83d762287f | ||
|
|
5af0acf147 | ||
|
|
907dfee6f7 | ||
|
|
d587d24603 | ||
|
|
c246b8f164 | ||
|
|
deecafa053 | ||
|
|
f8810106a2 |
213
.clang-format
213
.clang-format
@@ -1,105 +1,216 @@
|
|||||||
BasedOnStyle: Chromium
|
---
|
||||||
Language: Cpp
|
Language: Cpp
|
||||||
Standard: Cpp11
|
# BasedOnStyle: LLVM
|
||||||
AccessModifierOffset: -1
|
AccessModifierOffset: -1
|
||||||
AlignAfterOpenBracket: false
|
AlignAfterOpenBracket: Align
|
||||||
AlignConsecutiveAssignments: false
|
AlignArrayOfStructures: None
|
||||||
AlignConsecutiveDeclarations: false
|
AlignConsecutiveAssignments:
|
||||||
AlignConsecutiveMacros: true
|
Enabled: false
|
||||||
AlignEscapedNewlines: true
|
AcrossEmptyLines: false
|
||||||
AlignOperands: false
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
PadOperators: true
|
||||||
|
AlignConsecutiveBitFields:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveDeclarations:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveMacros:
|
||||||
|
Enabled: true
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignOperands: DontAlign
|
||||||
AlignTrailingComments: true
|
AlignTrailingComments: true
|
||||||
AllowAllArgumentsOnNextLine: false
|
AllowAllArgumentsOnNextLine: false
|
||||||
AllowAllConstructorInitializersOnNextLine: true
|
|
||||||
AllowAllParametersOfDeclarationOnNextLine: false
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
AllowShortBlocksOnASingleLine: false
|
AllowShortEnumsOnASingleLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: Never
|
||||||
AllowShortCaseLabelsOnASingleLine: true
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
AllowShortFunctionsOnASingleLine: true
|
AllowShortFunctionsOnASingleLine: All
|
||||||
AllowShortIfStatementsOnASingleLine: true
|
AllowShortLambdasOnASingleLine: All
|
||||||
AllowShortLambdasOnASingleLine: true
|
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
||||||
AllowShortLoopsOnASingleLine: true
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
AlwaysBreakAfterReturnType: None
|
AlwaysBreakAfterReturnType: None
|
||||||
AlwaysBreakBeforeMultilineStrings: false
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
AlwaysBreakTemplateDeclarations: No
|
AlwaysBreakTemplateDeclarations: No
|
||||||
|
AttributeMacros:
|
||||||
|
- __capability
|
||||||
BinPackArguments: true
|
BinPackArguments: true
|
||||||
BinPackParameters: true
|
BinPackParameters: true
|
||||||
BreakBeforeBraces: false
|
BraceWrapping:
|
||||||
BreakBeforeBinaryOperators: false
|
AfterCaseLabel: false
|
||||||
BreakBeforeBraces: Stroustrup
|
AfterClass: false
|
||||||
BreakBeforeTernaryOperators: false
|
AfterControlStatement: Never
|
||||||
BreakConstructorInitializers: BeforeColon
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
AfterExternBlock: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: true
|
||||||
|
BeforeLambdaBody: false
|
||||||
|
BeforeWhile: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: false
|
||||||
|
SplitEmptyRecord: false
|
||||||
|
SplitEmptyNamespace: false
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeConceptDeclarations: Always
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
BreakInheritanceList: BeforeColon
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakBeforeTernaryOperators: false
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
BreakStringLiterals: false
|
BreakStringLiterals: false
|
||||||
ColumnLimit: 0
|
ColumnLimit: 0
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
QualifierAlignment: Leave
|
||||||
CompactNamespaces: false
|
CompactNamespaces: false
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
|
||||||
ConstructorInitializerIndentWidth: 4
|
ConstructorInitializerIndentWidth: 4
|
||||||
ContinuationIndentWidth: 2
|
ContinuationIndentWidth: 2
|
||||||
Cpp11BracedListStyle: false
|
Cpp11BracedListStyle: false
|
||||||
DeriveLineEnding: true
|
DeriveLineEnding: true
|
||||||
DerivePointerAlignment: true
|
DerivePointerAlignment: false
|
||||||
DisableFormat: false
|
DisableFormat: false
|
||||||
ExperimentalAutoDetectBinPacking: true
|
EmptyLineAfterAccessModifier: Never
|
||||||
|
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
PackConstructorInitializers: BinPack
|
||||||
|
BasedOnStyle: ''
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
AllowAllConstructorInitializersOnNextLine: true
|
||||||
FixNamespaceComments: true
|
FixNamespaceComments: true
|
||||||
IncludeBlocks: Preserve
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IfMacros:
|
||||||
|
- KJ_IF_MAYBE
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||||
|
Priority: 2
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||||
|
Priority: 3
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IncludeIsMainSourceRegex: ''
|
||||||
|
IndentAccessModifiers: false
|
||||||
IndentCaseLabels: true
|
IndentCaseLabels: true
|
||||||
|
IndentCaseBlocks: false
|
||||||
IndentGotoLabels: true
|
IndentGotoLabels: true
|
||||||
IndentPPDirectives: AfterHash
|
IndentPPDirectives: AfterHash
|
||||||
IndentWidth: 2
|
IndentExternBlock: AfterExternBlock
|
||||||
|
IndentRequiresClause: true
|
||||||
|
IndentWidth: 2
|
||||||
IndentWrappedFunctionNames: false
|
IndentWrappedFunctionNames: false
|
||||||
|
InsertBraces: false
|
||||||
|
InsertTrailingCommas: None
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
LambdaBodyIndentation: Signature
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
MaxEmptyLinesToKeep: 100
|
MaxEmptyLinesToKeep: 100
|
||||||
NamespaceIndentation: None
|
NamespaceIndentation: None
|
||||||
|
ObjCBinPackProtocolList: Auto
|
||||||
ObjCBlockIndentWidth: 2
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCBreakBeforeNestedBlockParam: true
|
||||||
ObjCSpaceAfterProperty: false
|
ObjCSpaceAfterProperty: false
|
||||||
ObjCSpaceBeforeProtocolList: false
|
ObjCSpaceBeforeProtocolList: true
|
||||||
PenaltyBreakAssignment: 0
|
PenaltyBreakAssignment: 0
|
||||||
PenaltyBreakBeforeFirstCallParameter: 0
|
PenaltyBreakBeforeFirstCallParameter: 0
|
||||||
PenaltyBreakComment: 0
|
PenaltyBreakComment: 0
|
||||||
PenaltyBreakFirstLessLess: 0
|
PenaltyBreakFirstLessLess: 0
|
||||||
|
PenaltyBreakOpenParenthesis: 0
|
||||||
PenaltyBreakString: 0
|
PenaltyBreakString: 0
|
||||||
PenaltyBreakTemplateDeclaration: 0
|
PenaltyBreakTemplateDeclaration: 0
|
||||||
PenaltyExcessCharacter: 0
|
PenaltyExcessCharacter: 0
|
||||||
PenaltyReturnTypeOnItsOwnLine: 0
|
PenaltyReturnTypeOnItsOwnLine: 0
|
||||||
|
PenaltyIndentedWhitespace: 0
|
||||||
PointerAlignment: Right
|
PointerAlignment: Right
|
||||||
ReflowComments: false
|
PPIndentWidth: -1
|
||||||
SortIncludes: false
|
ReferenceAlignment: Pointer
|
||||||
|
ReflowComments: false
|
||||||
|
RemoveBracesLLVM: false
|
||||||
|
RequiresClausePosition: OwnLine
|
||||||
|
SeparateDefinitionBlocks: Leave
|
||||||
|
ShortNamespaceLines: 1
|
||||||
|
SortIncludes: false
|
||||||
|
SortJavaStaticImport: Before
|
||||||
SortUsingDeclarations: false
|
SortUsingDeclarations: false
|
||||||
SpaceAfterCStyleCast: false
|
SpaceAfterCStyleCast: false
|
||||||
SpaceAfterLogicalNot: false
|
SpaceAfterLogicalNot: false
|
||||||
SpaceAfterTemplateKeyword: false
|
SpaceAfterTemplateKeyword: false
|
||||||
SpaceBeforeAssignmentOperators: true
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCaseColon: false
|
||||||
SpaceBeforeCpp11BracedList: true
|
SpaceBeforeCpp11BracedList: true
|
||||||
SpaceBeforeCtorInitializerColon: true
|
SpaceBeforeCtorInitializerColon: true
|
||||||
SpaceBeforeInheritanceColon: true
|
SpaceBeforeInheritanceColon: true
|
||||||
SpaceBeforeParens: ControlStatements
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeParensOptions:
|
||||||
|
AfterControlStatements: true
|
||||||
|
AfterForeachMacros: true
|
||||||
|
AfterFunctionDefinitionName: false
|
||||||
|
AfterFunctionDeclarationName: false
|
||||||
|
AfterIfMacros: true
|
||||||
|
AfterOverloadedOperator: false
|
||||||
|
AfterRequiresInClause: false
|
||||||
|
AfterRequiresInExpression: false
|
||||||
|
BeforeNonEmptyParentheses: false
|
||||||
|
SpaceAroundPointerQualifiers: Default
|
||||||
SpaceBeforeRangeBasedForLoopColon: true
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
SpaceBeforeSquareBrackets: false
|
|
||||||
SpaceInEmptyBlock: false
|
SpaceInEmptyBlock: false
|
||||||
SpaceInEmptyParentheses: false
|
SpaceInEmptyParentheses: false
|
||||||
SpacesBeforeTrailingComments: 2
|
SpacesBeforeTrailingComments: 2
|
||||||
SpacesInAngles: false
|
SpacesInAngles: Never
|
||||||
SpacesInCStyleCastParentheses: false
|
|
||||||
SpacesInConditionalStatement: false
|
SpacesInConditionalStatement: false
|
||||||
SpacesInContainerLiterals: true
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInLineCommentPrefix:
|
||||||
|
Minimum: 1
|
||||||
|
Maximum: -1
|
||||||
SpacesInParentheses: false
|
SpacesInParentheses: false
|
||||||
SpacesInSquareBrackets: false
|
SpacesInSquareBrackets: false
|
||||||
UseCRLF: false
|
SpaceBeforeSquareBrackets: false
|
||||||
UseTab: Never
|
BitFieldColonSpacing: Both
|
||||||
BreakBeforeBraces: Custom
|
Standard: Latest
|
||||||
BraceWrapping:
|
StatementAttributeLikeMacros:
|
||||||
AfterFunction: false
|
- Q_EMIT
|
||||||
AfterCaseLabel: false
|
StatementMacros:
|
||||||
AfterStruct: false
|
- Q_UNUSED
|
||||||
AfterClass: false
|
- QT_REQUIRE_VERSION
|
||||||
AfterEnum: false
|
TabWidth: 8
|
||||||
AfterUnion: false
|
UseCRLF: false
|
||||||
AfterControlStatement: Never
|
UseTab: Never
|
||||||
AfterNamespace: false
|
WhitespaceSensitiveMacros:
|
||||||
AfterObjCDeclaration: false
|
- STRINGIZE
|
||||||
AfterExternBlock: false
|
- PP_STRINGIZE
|
||||||
BeforeCatch: false
|
- BOOST_PP_STRINGIZE
|
||||||
BeforeElse: true
|
- NS_SWIFT_NAME
|
||||||
SplitEmptyFunction: false
|
- CF_SWIFT_NAME
|
||||||
SplitEmptyRecord: false
|
...
|
||||||
SplitEmptyNamespace: false
|
|
||||||
|
|||||||
10
.github/ISSUE_TEMPLATE.md
vendored
10
.github/ISSUE_TEMPLATE.md
vendored
@@ -7,13 +7,9 @@ assignees: ''
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
For technical issues, questions and discussion please use the forum on https://forum.strawberrymusicplayer.org/
|
- [ ] I have checked the [FAQ](https://wiki.strawberrymusicplayer.org/wiki/FAQ) for answers.
|
||||||
Any issues related to feature requests will be closed. See the README for more details.
|
- [ ] I have checked the [Changelog](https://github.com/strawberrymusicplayer/strawberry/blob/master/Changelog) that the issue is not already fixed.
|
||||||
|
- [ ] I believe this issue is a bug, and not a general technical issue, question or feature requests that can be discussed on the [forum](https://forum.strawberrymusicplayer.org/).
|
||||||
Check the Changelog to see if the issue is already fixed:
|
|
||||||
https://github.com/strawberrymusicplayer/strawberry/blob/master/Changelog
|
|
||||||
|
|
||||||
If it's fixed, try the latest development build from: https://builds.strawberrymusicplayer.org/
|
|
||||||
|
|
||||||
**Describe the bug**
|
**Describe the bug**
|
||||||
A clear and concise description of what the bug is.
|
A clear and concise description of what the bug is.
|
||||||
|
|||||||
1054
.github/workflows/build.yml
vendored
Normal file
1054
.github/workflows/build.yml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2171
.github/workflows/ccpp.yml
vendored
2171
.github/workflows/ccpp.yml
vendored
File diff suppressed because it is too large
Load Diff
40
.gitignore
vendored
40
.gitignore
vendored
@@ -65,19 +65,6 @@ ui_*.h
|
|||||||
*.moc
|
*.moc
|
||||||
*.qm
|
*.qm
|
||||||
|
|
||||||
# QtCreator
|
|
||||||
CMakeLists.txt.user*
|
|
||||||
*.pro.user
|
|
||||||
*.pro.user.*
|
|
||||||
*creator.user*
|
|
||||||
target_wrapper.*
|
|
||||||
compile_commands.json
|
|
||||||
|
|
||||||
*.kdev4
|
|
||||||
*.vscode
|
|
||||||
*.code-workspace
|
|
||||||
*.sublime-workspace
|
|
||||||
|
|
||||||
# Temporary files
|
# Temporary files
|
||||||
*~
|
*~
|
||||||
*.autosave
|
*.autosave
|
||||||
@@ -105,22 +92,29 @@ Thumbs.db
|
|||||||
# Stuff in dist
|
# Stuff in dist
|
||||||
maketarball.sh
|
maketarball.sh
|
||||||
changelog
|
changelog
|
||||||
PKGBUILD
|
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
translations.pot
|
translations.pot
|
||||||
zanata.xml
|
zanata.xml
|
||||||
.zanata-cache/
|
.zanata-cache/
|
||||||
|
|
||||||
# Snap
|
# QtCreator
|
||||||
parts/
|
CMakeLists.txt.user*
|
||||||
prime/
|
*.pro.user
|
||||||
stage/
|
*.pro.user.*
|
||||||
*.snap
|
*creator.user*
|
||||||
/snap/.snapcraft/
|
target_wrapper.*
|
||||||
/*_source.tar.bz2
|
compile_commands.json
|
||||||
|
|
||||||
|
*.kdev4
|
||||||
|
*.vscode
|
||||||
|
*.code-workspace
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
# MSVC
|
# MSVC
|
||||||
CMakeSettings.json
|
CMakeSettings.json
|
||||||
/.vs/
|
/.vs
|
||||||
/out/
|
/out
|
||||||
|
|
||||||
|
# CLion
|
||||||
|
/.idea
|
||||||
|
|||||||
58
3rdparty/macdeployqt/shared.cpp
vendored
58
3rdparty/macdeployqt/shared.cpp
vendored
@@ -40,6 +40,8 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QVariantMap>
|
||||||
#include <QStack>
|
#include <QStack>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QLibraryInfo>
|
#include <QLibraryInfo>
|
||||||
@@ -187,9 +189,7 @@ OtoolInfo findDependencyInfo(const QString &binaryPath)
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QRegularExpression regexp(QStringLiteral(
|
static const QRegularExpression regexp(QStringLiteral("^\\t(.+) \\(compatibility version (\\d+\\.\\d+\\.\\d+), current version (\\d+\\.\\d+\\.\\d+)(, weak|, reexport)?\\)$"));
|
||||||
"^\\t(.+) \\(compatibility version (\\d+\\.\\d+\\.\\d+), "
|
|
||||||
"current version (\\d+\\.\\d+\\.\\d+)(, weak)?\\)$"));
|
|
||||||
|
|
||||||
QString output = otool.readAllStandardOutput();
|
QString output = otool.readAllStandardOutput();
|
||||||
QStringList outputLines = output.split("\n", Qt::SkipEmptyParts);
|
QStringList outputLines = output.split("\n", Qt::SkipEmptyParts);
|
||||||
@@ -220,6 +220,8 @@ OtoolInfo findDependencyInfo(const QString &binaryPath)
|
|||||||
for (const QString &outputLine : outputLines) {
|
for (const QString &outputLine : outputLines) {
|
||||||
const auto match = regexp.match(outputLine);
|
const auto match = regexp.match(outputLine);
|
||||||
if (match.hasMatch()) {
|
if (match.hasMatch()) {
|
||||||
|
if (match.captured(1) == info.installName)
|
||||||
|
continue; // Another arch reference to the same binary
|
||||||
DylibInfo dylib;
|
DylibInfo dylib;
|
||||||
dylib.binaryPath = match.captured(1);
|
dylib.binaryPath = match.captured(1);
|
||||||
dylib.compatibilityVersion = QVersionNumber::fromString(match.captured(2));
|
dylib.compatibilityVersion = QVersionNumber::fromString(match.captured(2));
|
||||||
@@ -300,11 +302,11 @@ FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundl
|
|||||||
if (state == QtPath) {
|
if (state == QtPath) {
|
||||||
// Check for library name part
|
// Check for library name part
|
||||||
if (part < parts.count() && parts.at(part).contains(".dylib")) {
|
if (part < parts.count() && parts.at(part).contains(".dylib")) {
|
||||||
info.frameworkDirectory += "/" + (qtPath + currentPart + "/").simplified();
|
info.frameworkDirectory += "/" + QString(qtPath + currentPart + "/").simplified();
|
||||||
state = DylibName;
|
state = DylibName;
|
||||||
continue;
|
continue;
|
||||||
} else if (part < parts.count() && parts.at(part).endsWith(".framework")) {
|
} else if (part < parts.count() && parts.at(part).endsWith(".framework")) {
|
||||||
info.frameworkDirectory += "/" + (qtPath + "lib/").simplified();
|
info.frameworkDirectory += "/" + QString(qtPath + "lib/").simplified();
|
||||||
state = FrameworkName;
|
state = FrameworkName;
|
||||||
continue;
|
continue;
|
||||||
} else if (trimmed.startsWith("/") == false) { // If the line does not contain a full path, the app is using a binary Qt package.
|
} else if (trimmed.startsWith("/") == false) { // If the line does not contain a full path, the app is using a binary Qt package.
|
||||||
@@ -865,6 +867,18 @@ void changeInstallName(const QString &bundlePath, const FrameworkInfo &framework
|
|||||||
if (!framework.installName.isEmpty() && framework.installName != framework.sourceFilePath) {
|
if (!framework.installName.isEmpty() && framework.installName != framework.sourceFilePath) {
|
||||||
changeInstallName(framework.installName, deployedInstallName, binary);
|
changeInstallName(framework.installName, deployedInstallName, binary);
|
||||||
}
|
}
|
||||||
|
// Workaround for the case when the library ID name is a symlink, while the dependencies
|
||||||
|
// specified using the canonical path to the library (QTBUG-56814)
|
||||||
|
QFileInfo fileInfo= QFileInfo(framework.installName);
|
||||||
|
QString canonicalInstallName = fileInfo.canonicalFilePath();
|
||||||
|
if (!canonicalInstallName.isEmpty() && canonicalInstallName != framework.installName) {
|
||||||
|
changeInstallName(canonicalInstallName, deployedInstallName, binary);
|
||||||
|
// some libraries' inner dependencies (such as ffmpeg, nettle) use symbol link (QTBUG-100093)
|
||||||
|
QString innerDependency = fileInfo.canonicalPath() + "/" + fileInfo.fileName();
|
||||||
|
if (innerDependency != canonicalInstallName && innerDependency != framework.installName) {
|
||||||
|
changeInstallName(innerDependency, deployedInstallName, binary);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1078,7 +1092,7 @@ QString getLibInfix(const QStringList &deployedFrameworks)
|
|||||||
{
|
{
|
||||||
QString libInfix;
|
QString libInfix;
|
||||||
for (const QString &framework : deployedFrameworks) {
|
for (const QString &framework : deployedFrameworks) {
|
||||||
if (framework.startsWith(QStringLiteral("QtCore")) && framework.endsWith(QStringLiteral(".framework"))) {
|
if (framework.startsWith(QStringLiteral("QtCore")) && framework.endsWith(QStringLiteral(".framework")) && !framework.contains(QStringLiteral("5Compat"))) {
|
||||||
Q_ASSERT(framework.length() >= 16);
|
Q_ASSERT(framework.length() >= 16);
|
||||||
// 16 == "QtCore" + ".framework"
|
// 16 == "QtCore" + ".framework"
|
||||||
const int lengthOfLibInfix = framework.length() - 16;
|
const int lengthOfLibInfix = framework.length() - 16;
|
||||||
@@ -1228,13 +1242,15 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
|
|||||||
}
|
}
|
||||||
|
|
||||||
const QStringList giomodules = QStringList() << "libgiognutls.so" << "libgioopenssl.so";
|
const QStringList giomodules = QStringList() << "libgiognutls.so" << "libgioopenssl.so";
|
||||||
|
bool have_giomodule = false;
|
||||||
for (const QString &giomodule : giomodules) {
|
for (const QString &giomodule : giomodules) {
|
||||||
const QString sourcePath = giomodule_path + "/" + giomodule;
|
const QString sourcePath = giomodule_path + "/" + giomodule;
|
||||||
QFileInfo fileinfo(sourcePath);
|
QFileInfo fileinfo(sourcePath);
|
||||||
if (!fileinfo.exists()) {
|
if (!fileinfo.exists()) {
|
||||||
LogError() << "Missing GIO module" << fileinfo.baseName();
|
LogError() << "Missing GIO module" << fileinfo.baseName();
|
||||||
qFatal("Missing GIO modules.");
|
continue;
|
||||||
}
|
}
|
||||||
|
have_giomodule = true;
|
||||||
const QString destinationPath = appBundleInfo.path + "/Contents/PlugIns/gio-modules/" + giomodule;
|
const QString destinationPath = appBundleInfo.path + "/Contents/PlugIns/gio-modules/" + giomodule;
|
||||||
QDir dir;
|
QDir dir;
|
||||||
if (dir.mkpath(QFileInfo(destinationPath).path()) && copyFilePrintStatus(sourcePath, destinationPath)) {
|
if (dir.mkpath(QFileInfo(destinationPath).path()) && copyFilePrintStatus(sourcePath, destinationPath)) {
|
||||||
@@ -1243,6 +1259,11 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
|
|||||||
deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath);
|
deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!have_giomodule) {
|
||||||
|
qFatal("Missing GIO modules.");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// gst-plugin-scanner
|
// gst-plugin-scanner
|
||||||
@@ -1270,6 +1291,7 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
|
|||||||
|
|
||||||
// GStreamer plugins.
|
// GStreamer plugins.
|
||||||
QStringList gstreamer_plugins = QStringList()
|
QStringList gstreamer_plugins = QStringList()
|
||||||
|
<< "libgstaes.dylib"
|
||||||
<< "libgstaiff.dylib"
|
<< "libgstaiff.dylib"
|
||||||
<< "libgstapetag.dylib"
|
<< "libgstapetag.dylib"
|
||||||
<< "libgstapp.dylib"
|
<< "libgstapp.dylib"
|
||||||
@@ -1288,13 +1310,16 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
|
|||||||
<< "libgstcoreelements.dylib"
|
<< "libgstcoreelements.dylib"
|
||||||
<< "libgstdash.dylib"
|
<< "libgstdash.dylib"
|
||||||
<< "libgstequalizer.dylib"
|
<< "libgstequalizer.dylib"
|
||||||
<< "libgstflac.dylib"
|
|
||||||
<< "libgstfaac.dylib"
|
<< "libgstfaac.dylib"
|
||||||
<< "libgstfaad.dylib"
|
<< "libgstfaad.dylib"
|
||||||
<< "libgstfdkaac.dylib"
|
<< "libgstfdkaac.dylib"
|
||||||
|
<< "libgstflac.dylib"
|
||||||
<< "libgstgio.dylib"
|
<< "libgstgio.dylib"
|
||||||
|
//<< "libgstgme.dylib"
|
||||||
|
<< "libgsthls.dylib"
|
||||||
<< "libgsticydemux.dylib"
|
<< "libgsticydemux.dylib"
|
||||||
<< "libgstid3demux.dylib"
|
<< "libgstid3demux.dylib"
|
||||||
|
<< "libgstid3tag.dylib"
|
||||||
<< "libgstisomp4.dylib"
|
<< "libgstisomp4.dylib"
|
||||||
<< "libgstlame.dylib"
|
<< "libgstlame.dylib"
|
||||||
<< "libgstlibav.dylib"
|
<< "libgstlibav.dylib"
|
||||||
@@ -1315,10 +1340,12 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
|
|||||||
<< "libgstspeex.dylib"
|
<< "libgstspeex.dylib"
|
||||||
<< "libgsttaglib.dylib"
|
<< "libgsttaglib.dylib"
|
||||||
<< "libgsttcp.dylib"
|
<< "libgsttcp.dylib"
|
||||||
|
<< "libgsttwolame.dylib"
|
||||||
<< "libgsttypefindfunctions.dylib"
|
<< "libgsttypefindfunctions.dylib"
|
||||||
<< "libgstudp.dylib"
|
<< "libgstudp.dylib"
|
||||||
<< "libgstvolume.dylib"
|
<< "libgstvolume.dylib"
|
||||||
<< "libgstvorbis.dylib"
|
<< "libgstvorbis.dylib"
|
||||||
|
<< "libgstwavenc.dylib"
|
||||||
<< "libgstwavpack.dylib"
|
<< "libgstwavpack.dylib"
|
||||||
<< "libgstwavparse.dylib"
|
<< "libgstwavparse.dylib"
|
||||||
<< "libgstxingmux.dylib";
|
<< "libgstxingmux.dylib";
|
||||||
@@ -1336,13 +1363,16 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList missing_gst_plugins;
|
||||||
|
|
||||||
for (const QString &plugin : gstreamer_plugins) {
|
for (const QString &plugin : gstreamer_plugins) {
|
||||||
QFileInfo info(gstreamer_plugins_dir + "/" + plugin);
|
QFileInfo info(gstreamer_plugins_dir + "/" + plugin);
|
||||||
if (!info.exists()) {
|
if (!info.exists()) {
|
||||||
info.setFile(gstreamer_plugins_dir + "/" + info.baseName() + QString(".so"));
|
info.setFile(gstreamer_plugins_dir + "/" + info.baseName() + QString(".so"));
|
||||||
if (!info.exists()) {
|
if (!info.exists()) {
|
||||||
LogError() << "Missing gstreamer plugin" << info.baseName();
|
LogError() << "Missing gstreamer plugin" << info.baseName();
|
||||||
qFatal("Missing %s", info.baseName().toUtf8().constData());
|
missing_gst_plugins << info.baseName();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const QString &sourcePath = info.filePath();
|
const QString &sourcePath = info.filePath();
|
||||||
@@ -1354,6 +1384,10 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!missing_gst_plugins.isEmpty()) {
|
||||||
|
LogError() << "Missing gstreamer plugins" << missing_gst_plugins;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void createQtConf(const QString &appBundlePath)
|
void createQtConf(const QString &appBundlePath)
|
||||||
@@ -1454,9 +1488,9 @@ bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInf
|
|||||||
for (const QString &importPath : qmlImportPaths)
|
for (const QString &importPath : qmlImportPaths)
|
||||||
argumentList << "-importPath" << importPath;
|
argumentList << "-importPath" << importPath;
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
QString qmlImportsPath = QLibraryInfo::path(QLibraryInfo::Qml2ImportsPath);
|
QString qmlImportsPath = QLibraryInfo::path(QLibraryInfo::QmlImportsPath);
|
||||||
#else
|
#else
|
||||||
QString qmlImportsPath = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
|
QString qmlImportsPath = QLibraryInfo::location(QLibraryInfo::QmlImportsPath);
|
||||||
#endif
|
#endif
|
||||||
argumentList.append( "-importPath");
|
argumentList.append( "-importPath");
|
||||||
argumentList.append(qmlImportsPath);
|
argumentList.append(qmlImportsPath);
|
||||||
@@ -1468,7 +1502,7 @@ bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInf
|
|||||||
LogError() << "Could not start qmlimpoortscanner. Process error is" << qmlImportScanner.errorString();
|
LogError() << "Could not start qmlimpoortscanner. Process error is" << qmlImportScanner.errorString();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
qmlImportScanner.waitForFinished();
|
qmlImportScanner.waitForFinished(-1);
|
||||||
|
|
||||||
// log qmlimportscanner errors
|
// log qmlimportscanner errors
|
||||||
qmlImportScanner.setReadChannel(QProcess::StandardError);
|
qmlImportScanner.setReadChannel(QProcess::StandardError);
|
||||||
|
|||||||
2
3rdparty/singleapplication/CMakeLists.txt
vendored
2
3rdparty/singleapplication/CMakeLists.txt
vendored
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.7)
|
||||||
|
|
||||||
include(CheckIncludeFiles)
|
include(CheckIncludeFiles)
|
||||||
include(CheckFunctionExists)
|
include(CheckFunctionExists)
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.7)
|
||||||
|
|
||||||
project(strawberry)
|
project(strawberry)
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.0)
|
|
||||||
cmake_policy(SET CMP0054 NEW)
|
cmake_policy(SET CMP0054 NEW)
|
||||||
|
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12)
|
||||||
|
cmake_policy(SET CMP0074 NEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
include(CheckCXXCompilerFlag)
|
include(CheckCXXCompilerFlag)
|
||||||
include(CheckCXXSourceRuns)
|
include(CheckCXXSourceRuns)
|
||||||
@@ -12,13 +16,13 @@ include(cmake/Summary.cmake)
|
|||||||
include(cmake/OptionalSource.cmake)
|
include(cmake/OptionalSource.cmake)
|
||||||
include(cmake/ParseArguments.cmake)
|
include(cmake/ParseArguments.cmake)
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
set(LINUX ON)
|
set(LINUX ON)
|
||||||
endif()
|
endif()
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
||||||
set(FREEBSD ON)
|
set(FREEBSD ON)
|
||||||
endif()
|
endif()
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
|
if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
|
||||||
set(OPENBSD ON)
|
set(OPENBSD ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -32,14 +36,22 @@ endif()
|
|||||||
|
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
set(CMAKE_C_STANDARD 99)
|
||||||
|
else()
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
list(APPEND COMPILE_OPTIONS /std:c++17 /MP)
|
list(APPEND COMPILE_OPTIONS /MP)
|
||||||
else()
|
else()
|
||||||
list(APPEND COMPILE_OPTIONS
|
list(APPEND COMPILE_OPTIONS
|
||||||
$<$<COMPILE_LANGUAGE:C>:-std=c99>
|
$<$<COMPILE_LANGUAGE:C>:-std=c11>
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-std=c++17>
|
$<$<COMPILE_LANGUAGE:CXX>:-std=c++17>
|
||||||
-Wall
|
-Wall
|
||||||
-Wextra
|
-Wextra
|
||||||
@@ -58,26 +70,24 @@ else()
|
|||||||
-Wformat=2
|
-Wformat=2
|
||||||
-Wdisabled-optimization
|
-Wdisabled-optimization
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-Woverloaded-virtual>
|
$<$<COMPILE_LANGUAGE:CXX>:-Woverloaded-virtual>
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-Wno-old-style-cast>
|
$<$<COMPILE_LANGUAGE:CXX>:-Wold-style-cast>
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-fpermissive>
|
|
||||||
)
|
)
|
||||||
endif()
|
option(BUILD_WERROR "Build with -Werror" OFF)
|
||||||
|
if(BUILD_WERROR)
|
||||||
option(BUILD_WERROR "Build with -Werror" OFF)
|
list(APPEND COMPILE_OPTIONS -Werror)
|
||||||
if(BUILD_WERROR)
|
endif()
|
||||||
list(APPEND COMPILE_OPTIONS -Werror)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_compile_options(${COMPILE_OPTIONS})
|
add_compile_options(${COMPILE_OPTIONS})
|
||||||
|
|
||||||
if(${CMAKE_BUILD_TYPE} MATCHES "Release")
|
if(CMAKE_BUILD_TYPE MATCHES "Release")
|
||||||
add_definitions(-DNDEBUG)
|
add_definitions(-DNDEBUG)
|
||||||
add_definitions(-DQT_NO_DEBUG_OUTPUT)
|
add_definitions(-DQT_NO_DEBUG_OUTPUT)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
option(USE_RPATH "Use RPATH" APPLE)
|
||||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
if(USE_RPATH)
|
||||||
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks")
|
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_program(CCACHE_EXECUTABLE NAMES ccache)
|
find_program(CCACHE_EXECUTABLE NAMES ccache)
|
||||||
@@ -87,6 +97,8 @@ if(CCACHE_EXECUTABLE)
|
|||||||
SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_EXECUTABLE})
|
SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_EXECUTABLE})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
option(USE_ICU "Use ICU" ON)
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
find_package(Boost REQUIRED)
|
find_package(Boost REQUIRED)
|
||||||
find_package(Threads)
|
find_package(Threads)
|
||||||
@@ -94,7 +106,14 @@ find_package(Backtrace)
|
|||||||
if(Backtrace_FOUND)
|
if(Backtrace_FOUND)
|
||||||
set(HAVE_BACKTRACE ON)
|
set(HAVE_BACKTRACE ON)
|
||||||
endif()
|
endif()
|
||||||
find_package(Iconv)
|
if(USE_ICU)
|
||||||
|
find_package(ICU COMPONENTS uc i18n REQUIRED)
|
||||||
|
if(ICU_FOUND)
|
||||||
|
set(HAVE_ICU ON)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
find_package(Iconv)
|
||||||
|
endif()
|
||||||
find_package(GnuTLS REQUIRED)
|
find_package(GnuTLS REQUIRED)
|
||||||
find_package(Protobuf REQUIRED)
|
find_package(Protobuf REQUIRED)
|
||||||
if(NOT Protobuf_PROTOC_EXECUTABLE)
|
if(NOT Protobuf_PROTOC_EXECUTABLE)
|
||||||
@@ -427,9 +446,9 @@ endif()
|
|||||||
|
|
||||||
option(INSTALL_TRANSLATIONS "Install translations" OFF)
|
option(INSTALL_TRANSLATIONS "Install translations" OFF)
|
||||||
|
|
||||||
optional_component(SUBSONIC ON "Subsonic support")
|
optional_component(SUBSONIC ON "Streaming: Subsonic")
|
||||||
optional_component(TIDAL ON "Tidal support")
|
optional_component(TIDAL ON "Streaming: Tidal")
|
||||||
optional_component(QOBUZ ON "Qobuz support")
|
optional_component(QOBUZ ON "Streaming: Qobuz")
|
||||||
|
|
||||||
optional_component(MOODBAR ON "Moodbar"
|
optional_component(MOODBAR ON "Moodbar"
|
||||||
DEPENDS "fftw3" FFTW3_FOUND
|
DEPENDS "fftw3" FFTW3_FOUND
|
||||||
@@ -490,12 +509,16 @@ endif()
|
|||||||
|
|
||||||
# Set up definitions
|
# Set up definitions
|
||||||
|
|
||||||
add_definitions(-DBOOST_BIND_NO_PLACEHOLDERS)
|
add_definitions(
|
||||||
add_definitions(${QT_DEFINITIONS})
|
-DBOOST_BIND_NO_PLACEHOLDERS
|
||||||
add_definitions(-DQT_STRICT_ITERATORS)
|
-DQT_STRICT_ITERATORS
|
||||||
add_definitions(-DQT_USE_QSTRINGBUILDER)
|
-DQT_NO_CAST_FROM_BYTEARRAY
|
||||||
add_definitions(-DQT_NO_URL_CAST_FROM_STRING)
|
-DQT_USE_QSTRINGBUILDER
|
||||||
add_definitions(-DQT_NO_CAST_TO_ASCII)
|
-DQT_NO_URL_CAST_FROM_STRING
|
||||||
|
-DQT_NO_CAST_TO_ASCII
|
||||||
|
-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT
|
||||||
|
-DQT_NO_FOREACH
|
||||||
|
)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
add_definitions(-DUNICODE)
|
add_definitions(-DUNICODE)
|
||||||
@@ -518,6 +541,10 @@ if(GTest_FOUND AND GMOCK_LIBRARY AND QtTest_LIBRARIES)
|
|||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(LINUX AND LSB_RELEASE_EXEC AND DPKG_BUILDPACKAGE)
|
||||||
|
add_subdirectory(debian)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Uninstall support
|
# Uninstall support
|
||||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
|
||||||
|
|
||||||
@@ -526,7 +553,7 @@ add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/c
|
|||||||
# Show a summary of what we have enabled
|
# Show a summary of what we have enabled
|
||||||
summary_show()
|
summary_show()
|
||||||
if(NOT HAVE_GSTREAMER AND NOT HAVE_VLC)
|
if(NOT HAVE_GSTREAMER AND NOT HAVE_VLC)
|
||||||
message(FATAL_ERROR "You need to have either GStreamer or VLC to compile!")
|
message(FATAL_ERROR "You need to have either GStreamer or libvlc to compile!")
|
||||||
elseif(NOT HAVE_GSTREAMER)
|
elseif(NOT HAVE_GSTREAMER)
|
||||||
message(WARNING "GStreamer is the only engine that is fully implemented. Using other engines is possible but not recommended.")
|
message(WARNING "GStreamer is the only engine that is fully implemented. Using other engines is possible but not recommended.")
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
144
Changelog
144
Changelog
@@ -2,6 +2,142 @@ Strawberry Music Player
|
|||||||
=======================
|
=======================
|
||||||
ChangeLog
|
ChangeLog
|
||||||
|
|
||||||
|
Version 1.0.13 (2023.01.09):
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed volume synchronization leading to infinite loop resulting in crash when adjusting volume while playing (#1089).
|
||||||
|
* Fixed incorrect volume.
|
||||||
|
* Fixed collection organizing incorrectly handling slashes inside {} brackets for variables (#1091).
|
||||||
|
* Fixed saving relative playlists to non-existing playlist files (#1092).
|
||||||
|
* Fixed intermittent crash on collection model query (#1095).
|
||||||
|
* Require system icons for fancy tabbar and settings sidebar to be larger than 22x22 (#1084).
|
||||||
|
|
||||||
|
Version 1.0.12 (2023.01.02):
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed crash when adjusting volume with mouse wheel (#1089).
|
||||||
|
* Fixed playback stopping in certain cases where the next track was unavailable (#958).
|
||||||
|
* (Windows) Apply patch for fonts too large on High DPI screen (QTBUG-108593).
|
||||||
|
|
||||||
|
Removed features:
|
||||||
|
* Removed appearance settings for changing palette colors, it was never properly implemented.
|
||||||
|
|
||||||
|
Version 1.0.11 (2022.12.30):
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Capitalize GLib application name so it appears nicely in GNOME and PulseAudio Volume Control (#1066).
|
||||||
|
* Fixed missing application icon for PulseAudio Volume Control (#1066).
|
||||||
|
* Ignore errors for missing albums when updating Tidal collection if there are results (#1061).
|
||||||
|
* Only run periodic collection scan when moitoring collection setting is on.
|
||||||
|
* Fixed an edge case where the context headline text was being cut short (#1067).
|
||||||
|
* Made "Show in file browser" support SpaceFM filemanager (#1073).
|
||||||
|
* Fixed incorrect tab order in edit tag dialog (#1075).
|
||||||
|
* Changed "FMPS_PlayCount" to "FMPS_Playcount" when saving tag (#1074).
|
||||||
|
* Fixed compilation tag read and write for MP4 (#1076).
|
||||||
|
* Removed incorrect use of "TPE1" for performer when reading ID3 tags (#1076).
|
||||||
|
* Disable tag fields for unsupported tags in tag editor.
|
||||||
|
* Don't allow organizing files without unique tags (track or title) for filename (#1077).
|
||||||
|
* Don't remove disc from album title when creating cover hash to allow different covers for each disc on an album (#1069).
|
||||||
|
* Fixed incorrect relative paths for song filenames when saving playlists if the saved playlist location is a symablic link to the song filename (#1071).
|
||||||
|
* Scrobble "Various Artists" as album artist (#1082).
|
||||||
|
|
||||||
|
Enhancements:
|
||||||
|
* Use system volume instead of own software volume when available (#1037).
|
||||||
|
* Improved Tidal and Qobuz support with timed requests.
|
||||||
|
* Support MPRIS2 xesam:userRating.
|
||||||
|
|
||||||
|
Version 1.0.10 (2022.10.21):
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed "Could not open settings file for writing: No such file or directory" error before settings file is created.
|
||||||
|
* Fixed visual glitch on currently playing track (#1051).
|
||||||
|
* Fixed "Unknown error" on Tidal search (#1047).
|
||||||
|
* Fixed incomplete lyrics from Genius.
|
||||||
|
* Fixed icons not showing in the file view on some systems (#1024).
|
||||||
|
* Fixed issues with context and playing widget stopping when using VLC (#1054).
|
||||||
|
* (macOS) Fixed search field related crash when playlist toolbar is turned off.
|
||||||
|
|
||||||
|
Enhancements:
|
||||||
|
* Fixed narrowing conversions in connects.
|
||||||
|
* Fixed casts from QByteArray.
|
||||||
|
* Removed subdir for generated dbus files
|
||||||
|
* Removed use of fixed font in context (#1040).
|
||||||
|
* Improve Musixmatch lyrics search.
|
||||||
|
|
||||||
|
Version 1.0.9 (2022.09.03):
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed parsing album title from radio stream metadata (#1023).
|
||||||
|
* (macOS) Fixed Strawberry not starting, incorrect rpath for libgcc_s.1.1.dylib (#1025).
|
||||||
|
* (macOS) Fixed HTTP streaming.
|
||||||
|
|
||||||
|
Version 1.0.8 (2022.08.29):
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed backslash being appended to filter text when switching playlist (#1005).
|
||||||
|
* Fixed OSD notifications service registering taking too long to timeout when not available.
|
||||||
|
* Fixed radio stream added twice when double-clicked (#1015).
|
||||||
|
* Fixed translating undo and redo buttons (#1017).
|
||||||
|
|
||||||
|
Enhancements:
|
||||||
|
* Use ICU instead of iconv to transliterate characters for filenames.
|
||||||
|
* Make separating albums by grouping tag optional in collection group by album.
|
||||||
|
* Added support for video game music formats VGM and SPC.
|
||||||
|
* Added setting for explicitly turning on HTTP/2 for streaming. Strawberry will set the
|
||||||
|
libsoup SOUP_FORCE_HTTP1 environment variable when the HTTP/2 is not checked (#1016).
|
||||||
|
* (Windows|MSVC) Install Visual C++ runtime redistributable automatically in installer.
|
||||||
|
|
||||||
|
Version 1.0.7 (2022.07.25)
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed checking file extension case-insensitive when loading and saving playlists.
|
||||||
|
* Fixed reading and saving rating with TagParser.
|
||||||
|
* (macOS/Windows) Fixed playlist column alignment. Applied patch for Qt bug QTBUG-103576 (#999).
|
||||||
|
* (Windows|MinGW) Fixed HLS streaming.
|
||||||
|
* (Windows|MSVC) Fixed MP3 encoding.
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
* Added option for selecting file extension when saving all playlists.
|
||||||
|
|
||||||
|
Version 1.0.6 (2022.07.17)
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed certain albums not added to playlist in correct track order from search for Tidal and QObuz.
|
||||||
|
* Fixed songs not added to playlist in numeric order when added from file view with right click (#977).
|
||||||
|
* Fixed "Stop after this track" graying out next track in dynamic mode (#912).
|
||||||
|
* Fixed a gstreamer caps leak when transcoding songs.
|
||||||
|
* Fixed errors in translation files (#994).
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
* Add songs to the collection even when they have invalid ctime or mtime.
|
||||||
|
* Made ListenBrainz scrobbler respect "Prefer album artist" option (#989).
|
||||||
|
* Send track duration, number, player name and version when scrobbling to ListenBrainz (#995).
|
||||||
|
* (macOS) Added missing HLS streaming plugin.
|
||||||
|
|
||||||
|
Version 1.0.5 (2022.06.10)
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed smart playlist filetype search.
|
||||||
|
* Fixed Radio Paradise URLs to use HTTPS instead of HTTP.
|
||||||
|
* Fixed horizontal scrolling not affecting currently playing track (#952).
|
||||||
|
* Fixed keep running in the background when window is closed with Wayland (#964).
|
||||||
|
* Fixed percent-encoding of URLs when loading and saving XSPF playlists (#821).
|
||||||
|
* Fixed fancy tabbar context menu showing on right clicks outside of tabbar when a song is playing.
|
||||||
|
* Fixed possible duplicating songs in the database when moving songs to the collection using the organize feature.
|
||||||
|
* (Windows|MSVC) Fixed moodbar fftw3 crash with (older) CPU's that does not support AVX2 (#944).
|
||||||
|
* (Windows|MSVC) Fixed using libiconv for converting characters when organizing files like with MinGW.
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
* Show more details in error dialog on GStreamer errors (#958).
|
||||||
|
* Allow setting blur amount of playlist background image up to 100px (#939).
|
||||||
|
* Include 128x128 icon sizes (#954).
|
||||||
|
* Show right click copy context menu in context view on top text and lyrics (#965).
|
||||||
|
* Improve fading between album covers in context view.
|
||||||
|
* Added option for overwriting database playcounts in collection settings (#962).
|
||||||
|
* Added option for disabling bar on currently playing track (#972).
|
||||||
|
* (Debian) Added Qt 6 support to debian files and build with Qt 6 for Debian Bookworm, Ubuntu Jammy and newer.
|
||||||
|
* (Windows|MSVC) Added libav/ffmpeg plugin.
|
||||||
|
|
||||||
Version 1.0.4 (2022.04.10)
|
Version 1.0.4 (2022.04.10)
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
@@ -158,7 +294,7 @@ Version 0.9.3 (2021.04.18)
|
|||||||
Bugfixes:
|
Bugfixes:
|
||||||
* Fix "Show in file browser" to work with thunar.
|
* Fix "Show in file browser" to work with thunar.
|
||||||
* Check that the clicked rating position is to the right or left of the rectangle.
|
* Check that the clicked rating position is to the right or left of the rectangle.
|
||||||
* Fix rescan when collection directory is removed and readded.
|
* Fix rescan when collection directory is removed and re-added.
|
||||||
* Create GLib main event loop on non-glib systems to fix stream discoverer.
|
* Create GLib main event loop on non-glib systems to fix stream discoverer.
|
||||||
* (macOS) Fix intermittent abort on startup.
|
* (macOS) Fix intermittent abort on startup.
|
||||||
* (macOS) Fix Tidal and Qobuz search field not showing.
|
* (macOS) Fix Tidal and Qobuz search field not showing.
|
||||||
@@ -495,7 +631,7 @@ Version 0.6.10 (2020.05.01)
|
|||||||
* Made font and font sizes in context configurable.
|
* Made font and font sizes in context configurable.
|
||||||
* Splitting artist and song title to the relevant metadata when artist and song title is sent as title separated by a dash in streams.
|
* Splitting artist and song title to the relevant metadata when artist and song title is sent as title separated by a dash in streams.
|
||||||
* Added label to show collection pixmap disk cache used in settings.
|
* Added label to show collection pixmap disk cache used in settings.
|
||||||
* Icreased default collection pixmap disk cache to 360.
|
* Increased default collection pixmap disk cache to 360.
|
||||||
|
|
||||||
New features:
|
New features:
|
||||||
* Added back Tidal streaming support.
|
* Added back Tidal streaming support.
|
||||||
@@ -563,7 +699,7 @@ Version 0.6.7 (2019.11.27)
|
|||||||
* Fixed "Pressing Previous in player" behaviour setting
|
* Fixed "Pressing Previous in player" behaviour setting
|
||||||
* Fixed updating compilations where there are spaces or special characters in filenames
|
* Fixed updating compilations where there are spaces or special characters in filenames
|
||||||
* Fixed cases where songs were stuck in "Various Artists" because not all songs in
|
* Fixed cases where songs were stuck in "Various Artists" because not all songs in
|
||||||
the same compilation was removed from the model before readded with actual artist.
|
the same compilation was removed from the model before re-added with actual artist.
|
||||||
* Fixed a bug when importing playlists where metadata was reset
|
* Fixed a bug when importing playlists where metadata was reset
|
||||||
* Fixed scrobbler to also scrobble songs without album title
|
* Fixed scrobbler to also scrobble songs without album title
|
||||||
* Fixed text for replay gain setting not loading in backend setting
|
* Fixed text for replay gain setting not loading in backend setting
|
||||||
@@ -916,7 +1052,7 @@ Version 0.1.5 (2018.05.16)
|
|||||||
|
|
||||||
|
|
||||||
Version 0.1.4 (2018.05.14)
|
Version 0.1.4 (2018.05.14)
|
||||||
* Fixed compliation with clang compiler
|
* Fixed compilation with clang compiler
|
||||||
* This release is mainly to get it working on openbsd and freebsd.
|
* This release is mainly to get it working on openbsd and freebsd.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
19
README.md
19
README.md
@@ -1,4 +1,4 @@
|
|||||||
:strawberry: Strawberry Music Player [](https://github.com/strawberrymusicplayer/strawberry/actions)
|
:strawberry: Strawberry Music Player [](https://github.com/strawberrymusicplayer/strawberry/actions)
|
||||||
=======================
|
=======================
|
||||||
[](https://github.com/sponsors/jonaski)
|
[](https://github.com/sponsors/jonaski)
|
||||||
[](https://patreon.com/jonaskvinge)
|
[](https://patreon.com/jonaskvinge)
|
||||||
@@ -11,6 +11,7 @@ Strawberry is a music player and music collection organizer. It is a fork of Cle
|
|||||||
Resources:
|
Resources:
|
||||||
|
|
||||||
* Website: https://www.strawberrymusicplayer.org/
|
* Website: https://www.strawberrymusicplayer.org/
|
||||||
|
* Wiki: https://wiki.strawberrymusicplayer.org/
|
||||||
* Forum: https://forum.strawberrymusicplayer.org/
|
* Forum: https://forum.strawberrymusicplayer.org/
|
||||||
* Github: https://github.com/strawberrymusicplayer/strawberry
|
* Github: https://github.com/strawberrymusicplayer/strawberry
|
||||||
* Buildbot: https://buildbot.strawberrymusicplayer.org/
|
* Buildbot: https://buildbot.strawberrymusicplayer.org/
|
||||||
@@ -22,6 +23,7 @@ Resources:
|
|||||||
|
|
||||||
### :bangbang: Opening an issue:
|
### :bangbang: Opening an issue:
|
||||||
|
|
||||||
|
* Read the FAQ: https://wiki.strawberrymusicplayer.org/wiki/FAQ
|
||||||
* Search for the issue to see if it is already solved, or if there is an open issue for it already. If there is an open issue already, you can comment on it if you have additional information that could be useful to us.
|
* Search for the issue to see if it is already solved, or if there is an open issue for it already. If there is an open issue already, you can comment on it if you have additional information that could be useful to us.
|
||||||
* For technical problems, discussion, questions and feature suggestions use the forum (https://forum.strawberrymusicplayer.org/) instead. The forum is better suited for discussion.
|
* For technical problems, discussion, questions and feature suggestions use the forum (https://forum.strawberrymusicplayer.org/) instead. The forum is better suited for discussion.
|
||||||
* We do not take feature requests from users on GitHub. Any issues related to feature requests will be closed. This does not necessarily mean that we won't add new features, but we don't have time to take feature requests or answer questions about new features from users. It is still possible to suggest or discuss new features on the forum (https://forum.strawberrymusicplayer.org/).
|
* We do not take feature requests from users on GitHub. Any issues related to feature requests will be closed. This does not necessarily mean that we won't add new features, but we don't have time to take feature requests or answer questions about new features from users. It is still possible to suggest or discuss new features on the forum (https://forum.strawberrymusicplayer.org/).
|
||||||
@@ -67,10 +69,11 @@ It has so far been tested to work on Linux, OpenBSD, FreeBSD, macOS and Windows.
|
|||||||
To build Strawberry from source you need the following installed on your system with the additional development packages/headers:
|
To build Strawberry from source you need the following installed on your system with the additional development packages/headers:
|
||||||
|
|
||||||
* [CMake](https://cmake.org/)
|
* [CMake](https://cmake.org/)
|
||||||
* [GCC](https://gcc.gnu.org/), [Clang](https://clang.llvm.org/) or [MSVC](https://visualstudio.microsoft.com/vs/features/cplusplus/) compiler
|
* C/C++ compiler ([GCC](https://gcc.gnu.org/), [Clang](https://clang.llvm.org/) or [MSVC](https://visualstudio.microsoft.com/vs/features/cplusplus/))
|
||||||
|
* [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/) or [pkgconf](https://github.com/pkgconf/pkgconf)
|
||||||
* [Boost](https://www.boost.org/)
|
* [Boost](https://www.boost.org/)
|
||||||
* [GLib](https://developer.gnome.org/glib/)
|
* [GLib](https://developer.gnome.org/glib/)
|
||||||
* [Qt 5.9 or higher (or Qt 6) with components Core, Gui, Widgets, Concurrent, Network and Sql](https://www.qt.io/)
|
* [Qt 6 or Qt 5.9 or higher with components Core, Gui, Widgets, Concurrent, Network and Sql](https://www.qt.io/)
|
||||||
* [SQLite 3.9 or newer with FTS5](https://www.sqlite.org)
|
* [SQLite 3.9 or newer with FTS5](https://www.sqlite.org)
|
||||||
* [Protobuf](https://developers.google.com/protocol-buffers/)
|
* [Protobuf](https://developers.google.com/protocol-buffers/)
|
||||||
* [ALSA (Required on Linux)](https://www.alsa-project.org/)
|
* [ALSA (Required on Linux)](https://www.alsa-project.org/)
|
||||||
@@ -78,6 +81,7 @@ To build Strawberry from source you need the following installed on your system
|
|||||||
* [GStreamer](https://gstreamer.freedesktop.org/) or [VLC](https://www.videolan.org)
|
* [GStreamer](https://gstreamer.freedesktop.org/) or [VLC](https://www.videolan.org)
|
||||||
* [GnuTLS](https://www.gnutls.org/)
|
* [GnuTLS](https://www.gnutls.org/)
|
||||||
* [TagLib 1.11.1 or higher](https://www.taglib.org/) or [TagParser](https://github.com/Martchus/tagparser)
|
* [TagLib 1.11.1 or higher](https://www.taglib.org/) or [TagParser](https://github.com/Martchus/tagparser)
|
||||||
|
* [ICU](https://unicode-org.github.io/icu/)
|
||||||
|
|
||||||
Optional dependencies:
|
Optional dependencies:
|
||||||
|
|
||||||
@@ -99,16 +103,19 @@ You should also install the gstreamer plugins base and good, and optionally bad,
|
|||||||
### Compile and install:
|
### Compile and install:
|
||||||
|
|
||||||
cd strawberry
|
cd strawberry
|
||||||
mkdir build && cd build
|
mkdir build
|
||||||
|
cd build
|
||||||
cmake .. -DBUILD_WITH_QT6=ON
|
cmake .. -DBUILD_WITH_QT6=ON
|
||||||
make -j$(nproc)
|
make -j $(nproc)
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
||||||
Strawberry is backwards compatible with Qt 5, to compile with Qt 5 use:
|
Strawberry is backwards compatible with Qt 5, to compile with Qt 5 use:
|
||||||
|
|
||||||
cmake .. -DBUILD_WITH_QT5=ON
|
cmake .. -DBUILD_WITH_QT5=ON
|
||||||
|
|
||||||
|
To compile on Windows with Visual Studio 2019 or 2022, see https://github.com/strawberrymusicplayer/strawberry-msvc
|
||||||
|
|
||||||
### :penguin: Packaging status
|
### :penguin: Packaging status
|
||||||
|
|
||||||
[](https://repology.org/metapackage/strawberry/versions)
|
[](https://repology.org/metapackage/strawberry/versions)
|
||||||
|
|
||||||
|
|||||||
@@ -2,18 +2,5 @@ find_program(LSB_RELEASE_EXEC lsb_release)
|
|||||||
find_program(DPKG_BUILDPACKAGE dpkg-buildpackage)
|
find_program(DPKG_BUILDPACKAGE dpkg-buildpackage)
|
||||||
|
|
||||||
if (LSB_RELEASE_EXEC AND DPKG_BUILDPACKAGE)
|
if (LSB_RELEASE_EXEC AND DPKG_BUILDPACKAGE)
|
||||||
execute_process(COMMAND env LC_ALL=C date "+%a, %-d %b %Y %H:%M:%S %z" OUTPUT_VARIABLE DEB_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
|
add_custom_target(deb WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${DPKG_BUILDPACKAGE} -b -d -uc -us)
|
||||||
|
|
||||||
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -cs"
|
|
||||||
OUTPUT_VARIABLE DEB_CODENAME
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
||||||
)
|
|
||||||
|
|
||||||
if (DEB_CODENAME AND DEB_DATE)
|
|
||||||
add_custom_target(deb
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
||||||
COMMAND ${DPKG_BUILDPACKAGE} -b -d -uc -us
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
set(STRAWBERRY_VERSION_MAJOR 1)
|
set(STRAWBERRY_VERSION_MAJOR 1)
|
||||||
set(STRAWBERRY_VERSION_MINOR 0)
|
set(STRAWBERRY_VERSION_MINOR 0)
|
||||||
set(STRAWBERRY_VERSION_PATCH 4)
|
set(STRAWBERRY_VERSION_PATCH 13)
|
||||||
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
||||||
|
|
||||||
set(INCLUDE_GIT_REVISION OFF)
|
set(INCLUDE_GIT_REVISION OFF)
|
||||||
@@ -14,10 +14,6 @@ set(STRAWBERRY_VERSION_RPM_R "1")
|
|||||||
set(STRAWBERRY_VERSION_PAC_V "${majorminorpatch}")
|
set(STRAWBERRY_VERSION_PAC_V "${majorminorpatch}")
|
||||||
set(STRAWBERRY_VERSION_PAC_R "1")
|
set(STRAWBERRY_VERSION_PAC_R "1")
|
||||||
|
|
||||||
if(${STRAWBERRY_VERSION_PATCH} EQUAL "0")
|
|
||||||
set(STRAWBERRY_VERSION_DISPLAY "${STRAWBERRY_VERSION_MAJOR}.${STRAWBERRY_VERSION_MINOR}")
|
|
||||||
endif(${STRAWBERRY_VERSION_PATCH} EQUAL "0")
|
|
||||||
|
|
||||||
if(STRAWBERRY_VERSION_PRERELEASE)
|
if(STRAWBERRY_VERSION_PRERELEASE)
|
||||||
set(STRAWBERRY_VERSION_DISPLAY "${STRAWBERRY_VERSION_DISPLAY} ${STRAWBERRY_VERSION_PRERELEASE}")
|
set(STRAWBERRY_VERSION_DISPLAY "${STRAWBERRY_VERSION_DISPLAY} ${STRAWBERRY_VERSION_PRERELEASE}")
|
||||||
set(STRAWBERRY_VERSION_RPM_R "0.${STRAWBERRY_VERSION_PRERELEASE}")
|
set(STRAWBERRY_VERSION_RPM_R "0.${STRAWBERRY_VERSION_PRERELEASE}")
|
||||||
|
|||||||
@@ -1,15 +1,6 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
<file>schema/schema.sql</file>
|
<file>schema/schema.sql</file>
|
||||||
<file>schema/schema-1.sql</file>
|
|
||||||
<file>schema/schema-2.sql</file>
|
|
||||||
<file>schema/schema-3.sql</file>
|
|
||||||
<file>schema/schema-4.sql</file>
|
|
||||||
<file>schema/schema-5.sql</file>
|
|
||||||
<file>schema/schema-6.sql</file>
|
|
||||||
<file>schema/schema-7.sql</file>
|
|
||||||
<file>schema/schema-8.sql</file>
|
|
||||||
<file>schema/schema-9.sql</file>
|
|
||||||
<file>schema/schema-10.sql</file>
|
<file>schema/schema-10.sql</file>
|
||||||
<file>schema/schema-11.sql</file>
|
<file>schema/schema-11.sql</file>
|
||||||
<file>schema/schema-12.sql</file>
|
<file>schema/schema-12.sql</file>
|
||||||
|
|||||||
@@ -1,35 +1,35 @@
|
|||||||
CREATE TABLE device_%deviceid_directories (
|
CREATE TABLE device_%deviceid_directories (
|
||||||
path TEXT NOT NULL DEFAULT '',
|
path TEXT NOT NULL,
|
||||||
subdirs INTEGER NOT NULL
|
subdirs INTEGER NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE device_%deviceid_subdirectories (
|
CREATE TABLE device_%deviceid_subdirectories (
|
||||||
directory_id INTEGER NOT NULL,
|
directory_id INTEGER NOT NULL,
|
||||||
path TEXT NOT NULL DEFAULT '',
|
path TEXT NOT NULL,
|
||||||
mtime INTEGER NOT NULL
|
mtime INTEGER NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE device_%deviceid_songs (
|
CREATE TABLE device_%deviceid_songs (
|
||||||
|
|
||||||
title TEXT DEFAULT '',
|
title TEXT,
|
||||||
album TEXT DEFAULT '',
|
album TEXT,
|
||||||
artist TEXT DEFAULT '',
|
artist TEXT,
|
||||||
albumartist TEXT DEFAULT '',
|
albumartist TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||||
genre TEXT DEFAULT '',
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT DEFAULT '',
|
composer TEXT,
|
||||||
performer TEXT DEFAULT '',
|
performer TEXT,
|
||||||
grouping TEXT DEFAULT '',
|
grouping TEXT,
|
||||||
comment TEXT DEFAULT '',
|
comment TEXT,
|
||||||
lyrics TEXT DEFAULT '',
|
lyrics TEXT,
|
||||||
|
|
||||||
artist_id TEXT DEFAULT '',
|
artist_id TEXT,
|
||||||
album_id TEXT DEFAULT '',
|
album_id TEXT,
|
||||||
song_id TEXT DEFAULT '',
|
song_id TEXT,
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
beginning INTEGER NOT NULL DEFAULT 0,
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
length INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -40,14 +40,14 @@ CREATE TABLE device_%deviceid_songs (
|
|||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
source INTEGER NOT NULL DEFAULT 0,
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||||
url TEXT NOT NULL DEFAULT '',
|
url TEXT NOT NULL,
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
filetype INTEGER NOT NULL DEFAULT 0,
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
filesize INTEGER NOT NULL DEFAULT -1,
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
mtime INTEGER NOT NULL DEFAULT -1,
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
ctime INTEGER NOT NULL DEFAULT -1,
|
||||||
unavailable INTEGER DEFAULT 0,
|
unavailable INTEGER DEFAULT 0,
|
||||||
|
|
||||||
fingerprint TEXT DEFAULT '',
|
fingerprint TEXT,
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
playcount INTEGER NOT NULL DEFAULT 0,
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -59,13 +59,13 @@ CREATE TABLE device_%deviceid_songs (
|
|||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
art_automatic TEXT DEFAULT '',
|
art_automatic TEXT,
|
||||||
art_manual TEXT DEFAULT '',
|
art_manual TEXT,
|
||||||
|
|
||||||
effective_albumartist TEXT DEFAULT '',
|
effective_albumartist TEXT,
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
cue_path TEXT DEFAULT '',
|
cue_path TEXT,
|
||||||
|
|
||||||
rating INTEGER DEFAULT -1
|
rating INTEGER DEFAULT -1
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
ALTER TABLE playlist_items ADD COLUMN internet_service TEXT;
|
|
||||||
|
|
||||||
UPDATE schema_version SET version=1;
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
ALTER TABLE %allsongstables ADD COLUMN fingerprint TEXT DEFAULT '';
|
ALTER TABLE %allsongstables ADD COLUMN fingerprint TEXT;
|
||||||
|
|
||||||
ALTER TABLE %allsongstables ADD COLUMN lastseen INTEGER NOT NULL DEFAULT -1;
|
ALTER TABLE %allsongstables ADD COLUMN lastseen INTEGER NOT NULL DEFAULT -1;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
CREATE TABLE IF NOT EXISTS radio_channels (
|
CREATE TABLE IF NOT EXISTS radio_channels (
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
source INTEGER NOT NULL DEFAULT 0,
|
||||||
name TEXT DEFAULT '',
|
name TEXT NOT NULL,
|
||||||
url TEXT DEFAULT '',
|
url TEXT NOT NULL,
|
||||||
thumbnail_url TEXT DEFAULT ''
|
thumbnail_url TEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
UPDATE schema_version SET version=15;
|
UPDATE schema_version SET version=15;
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
ALTER TABLE songs ADD COLUMN lyrics TEXT;
|
|
||||||
|
|
||||||
ALTER TABLE playlist_items ADD COLUMN lyrics TEXT;
|
|
||||||
|
|
||||||
UPDATE schema_version SET version=2;
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
ALTER TABLE songs ADD COLUMN source INTEGER NOT NULL DEFAULT 0;
|
|
||||||
|
|
||||||
UPDATE songs SET source = 2 WHERE source = 0;
|
|
||||||
|
|
||||||
DROP TABLE playlist_items;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS playlist_items (
|
|
||||||
|
|
||||||
playlist INTEGER NOT NULL,
|
|
||||||
type INTEGER NOT NULL DEFAULT 0,
|
|
||||||
collection_id INTEGER,
|
|
||||||
url TEXT,
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT 0,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT 0,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER,
|
|
||||||
filename TEXT,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER,
|
|
||||||
mtime INTEGER,
|
|
||||||
ctime INTEGER,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
UPDATE schema_version SET version=3;
|
|
||||||
@@ -1,205 +0,0 @@
|
|||||||
CREATE TABLE IF NOT EXISTS tidal_artists_songs (
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT 0,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT 0,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER NOT NULL,
|
|
||||||
filename TEXT NOT NULL,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER NOT NULL DEFAULT 0,
|
|
||||||
mtime INTEGER NOT NULL DEFAULT 0,
|
|
||||||
ctime INTEGER NOT NULL DEFAULT 0,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS tidal_albums_songs (
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT 0,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT 0,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER NOT NULL,
|
|
||||||
filename TEXT NOT NULL,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER NOT NULL DEFAULT 0,
|
|
||||||
mtime INTEGER NOT NULL DEFAULT 0,
|
|
||||||
ctime INTEGER NOT NULL DEFAULT 0,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS tidal_songs (
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT 0,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT 0,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER NOT NULL,
|
|
||||||
filename TEXT NOT NULL,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER NOT NULL DEFAULT 0,
|
|
||||||
mtime INTEGER NOT NULL DEFAULT 0,
|
|
||||||
ctime INTEGER NOT NULL DEFAULT 0,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE VIRTUAL TABLE IF NOT EXISTS tidal_artists_songs_fts USING fts3(
|
|
||||||
|
|
||||||
ftstitle,
|
|
||||||
ftsalbum,
|
|
||||||
ftsartist,
|
|
||||||
ftsalbumartist,
|
|
||||||
ftscomposer,
|
|
||||||
ftsperformer,
|
|
||||||
ftsgrouping,
|
|
||||||
ftsgenre,
|
|
||||||
ftscomment,
|
|
||||||
tokenize=unicode
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE VIRTUAL TABLE IF NOT EXISTS tidal_albums_songs_fts USING fts3(
|
|
||||||
|
|
||||||
ftstitle,
|
|
||||||
ftsalbum,
|
|
||||||
ftsartist,
|
|
||||||
ftsalbumartist,
|
|
||||||
ftscomposer,
|
|
||||||
ftsperformer,
|
|
||||||
ftsgrouping,
|
|
||||||
ftsgenre,
|
|
||||||
ftscomment,
|
|
||||||
tokenize=unicode
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE VIRTUAL TABLE IF NOT EXISTS tidal_songs_fts USING fts3(
|
|
||||||
|
|
||||||
ftstitle,
|
|
||||||
ftsalbum,
|
|
||||||
ftsartist,
|
|
||||||
ftsalbumartist,
|
|
||||||
ftscomposer,
|
|
||||||
ftsperformer,
|
|
||||||
ftsgrouping,
|
|
||||||
ftsgenre,
|
|
||||||
ftscomment,
|
|
||||||
tokenize=unicode
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
UPDATE schema_version SET version=4;
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
ALTER TABLE songs ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
|
|
||||||
|
|
||||||
ALTER TABLE songs ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
|
|
||||||
|
|
||||||
ALTER TABLE songs ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
|
|
||||||
|
|
||||||
ALTER TABLE tidal_artists_songs ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
|
|
||||||
|
|
||||||
ALTER TABLE tidal_artists_songs ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
|
|
||||||
|
|
||||||
ALTER TABLE tidal_artists_songs ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
|
|
||||||
|
|
||||||
ALTER TABLE tidal_albums_songs ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
|
|
||||||
|
|
||||||
ALTER TABLE tidal_albums_songs ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
|
|
||||||
|
|
||||||
ALTER TABLE tidal_albums_songs ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
|
|
||||||
|
|
||||||
ALTER TABLE tidal_songs ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
|
|
||||||
|
|
||||||
ALTER TABLE tidal_songs ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
|
|
||||||
|
|
||||||
ALTER TABLE tidal_songs ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
|
|
||||||
|
|
||||||
ALTER TABLE playlist_items ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
|
|
||||||
|
|
||||||
ALTER TABLE playlist_items ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
|
|
||||||
|
|
||||||
ALTER TABLE playlist_items ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
|
|
||||||
|
|
||||||
UPDATE schema_version SET version=5;
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
CREATE TABLE IF NOT EXISTS subsonic_songs (
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
album_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
song_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT 0,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT 0,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER NOT NULL,
|
|
||||||
filename TEXT NOT NULL,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER NOT NULL DEFAULT 0,
|
|
||||||
mtime INTEGER NOT NULL DEFAULT 0,
|
|
||||||
ctime INTEGER NOT NULL DEFAULT 0,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE VIRTUAL TABLE IF NOT EXISTS subsonic_songs_fts USING fts3(
|
|
||||||
|
|
||||||
ftstitle,
|
|
||||||
ftsalbum,
|
|
||||||
ftsartist,
|
|
||||||
ftsalbumartist,
|
|
||||||
ftscomposer,
|
|
||||||
ftsperformer,
|
|
||||||
ftsgrouping,
|
|
||||||
ftsgenre,
|
|
||||||
ftscomment,
|
|
||||||
tokenize=unicode
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
UPDATE schema_version SET version=6;
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
album_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
song_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT 0,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT 0,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER NOT NULL,
|
|
||||||
filename TEXT NOT NULL,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER NOT NULL DEFAULT 0,
|
|
||||||
mtime INTEGER NOT NULL DEFAULT 0,
|
|
||||||
ctime INTEGER NOT NULL DEFAULT 0,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
album_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
song_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT 0,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT 0,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER NOT NULL,
|
|
||||||
filename TEXT NOT NULL,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER NOT NULL DEFAULT 0,
|
|
||||||
mtime INTEGER NOT NULL DEFAULT 0,
|
|
||||||
ctime INTEGER NOT NULL DEFAULT 0,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS qobuz_songs (
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
album_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
song_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT 0,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT 0,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER NOT NULL,
|
|
||||||
filename TEXT NOT NULL,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER NOT NULL DEFAULT 0,
|
|
||||||
mtime INTEGER NOT NULL DEFAULT 0,
|
|
||||||
ctime INTEGER NOT NULL DEFAULT 0,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE VIRTUAL TABLE IF NOT EXISTS qobuz_artists_songs_fts USING fts3(
|
|
||||||
|
|
||||||
ftstitle,
|
|
||||||
ftsalbum,
|
|
||||||
ftsartist,
|
|
||||||
ftsalbumartist,
|
|
||||||
ftscomposer,
|
|
||||||
ftsperformer,
|
|
||||||
ftsgrouping,
|
|
||||||
ftsgenre,
|
|
||||||
ftscomment,
|
|
||||||
tokenize=unicode
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE VIRTUAL TABLE IF NOT EXISTS qobuz_albums_songs_fts USING fts3(
|
|
||||||
|
|
||||||
ftstitle,
|
|
||||||
ftsalbum,
|
|
||||||
ftsartist,
|
|
||||||
ftsalbumartist,
|
|
||||||
ftscomposer,
|
|
||||||
ftsperformer,
|
|
||||||
ftsgrouping,
|
|
||||||
ftsgenre,
|
|
||||||
ftscomment,
|
|
||||||
tokenize=unicode
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE VIRTUAL TABLE IF NOT EXISTS qobuz_songs_fts USING fts3(
|
|
||||||
|
|
||||||
ftstitle,
|
|
||||||
ftsalbum,
|
|
||||||
ftsartist,
|
|
||||||
ftsalbumartist,
|
|
||||||
ftscomposer,
|
|
||||||
ftsperformer,
|
|
||||||
ftsgrouping,
|
|
||||||
ftsgenre,
|
|
||||||
ftscomment,
|
|
||||||
tokenize=unicode
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
UPDATE schema_version SET version=7;
|
|
||||||
@@ -1,595 +0,0 @@
|
|||||||
ALTER TABLE songs RENAME TO songs_old;
|
|
||||||
|
|
||||||
ALTER TABLE playlist_items RENAME TO playlist_items_old;
|
|
||||||
|
|
||||||
ALTER TABLE tidal_artists_songs RENAME TO tidal_artists_songs_old;
|
|
||||||
|
|
||||||
ALTER TABLE tidal_albums_songs RENAME TO tidal_albums_songs_old;
|
|
||||||
|
|
||||||
ALTER TABLE tidal_songs RENAME TO tidal_songs_old;
|
|
||||||
|
|
||||||
ALTER TABLE qobuz_artists_songs RENAME TO qobuz_artists_songs_old;
|
|
||||||
|
|
||||||
ALTER TABLE qobuz_albums_songs RENAME TO qobuz_albums_songs_old;
|
|
||||||
|
|
||||||
ALTER TABLE qobuz_songs RENAME TO qobuz_songs_old;
|
|
||||||
|
|
||||||
ALTER TABLE subsonic_songs RENAME TO subsonic_songs_old;
|
|
||||||
|
|
||||||
DROP INDEX idx_filename;
|
|
||||||
|
|
||||||
CREATE TABLE songs (
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
album_id TEXT NOT NULL,
|
|
||||||
song_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
url TEXT NOT NULL,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE tidal_artists_songs (
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
album_id TEXT NOT NULL,
|
|
||||||
song_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
url TEXT NOT NULL,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE tidal_albums_songs (
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
album_id TEXT NOT NULL,
|
|
||||||
song_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
url TEXT NOT NULL,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE tidal_songs (
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
album_id TEXT NOT NULL,
|
|
||||||
song_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
url TEXT NOT NULL,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE subsonic_songs (
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
album_id TEXT NOT NULL,
|
|
||||||
song_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
url TEXT NOT NULL,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE qobuz_artists_songs (
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
album_id TEXT NOT NULL,
|
|
||||||
song_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
url TEXT NOT NULL,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE qobuz_albums_songs (
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
album_id TEXT NOT NULL,
|
|
||||||
song_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
url TEXT NOT NULL,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE qobuz_songs (
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
album_id TEXT NOT NULL,
|
|
||||||
song_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
url TEXT NOT NULL,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE playlist_items (
|
|
||||||
|
|
||||||
playlist INTEGER NOT NULL,
|
|
||||||
type INTEGER NOT NULL DEFAULT 0,
|
|
||||||
collection_id INTEGER,
|
|
||||||
playlist_url TEXT,
|
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
album TEXT NOT NULL,
|
|
||||||
artist TEXT NOT NULL,
|
|
||||||
albumartist TEXT NOT NULL,
|
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
|
||||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
genre TEXT NOT NULL,
|
|
||||||
compilation INTEGER NOT NULL DEFAULT -1,
|
|
||||||
composer TEXT NOT NULL,
|
|
||||||
performer TEXT NOT NULL,
|
|
||||||
grouping TEXT NOT NULL,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
lyrics TEXT NOT NULL,
|
|
||||||
|
|
||||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
album_id TEXT NOT NULL,
|
|
||||||
song_id INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
|
||||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
|
||||||
directory_id INTEGER,
|
|
||||||
url TEXT,
|
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
|
||||||
filesize INTEGER,
|
|
||||||
mtime INTEGER,
|
|
||||||
ctime INTEGER,
|
|
||||||
unavailable INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
|
||||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
|
||||||
|
|
||||||
compilation_detected INTEGER DEFAULT 0,
|
|
||||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
art_automatic TEXT,
|
|
||||||
art_manual TEXT,
|
|
||||||
|
|
||||||
effective_albumartist TEXT,
|
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
cue_path TEXT
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
INSERT INTO songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
|
||||||
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
|
||||||
FROM songs_old;
|
|
||||||
|
|
||||||
DROP TABLE songs_old;
|
|
||||||
|
|
||||||
INSERT INTO tidal_artists_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
|
||||||
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
|
||||||
FROM tidal_artists_songs_old;
|
|
||||||
|
|
||||||
DROP TABLE tidal_artists_songs_old;
|
|
||||||
|
|
||||||
INSERT INTO tidal_albums_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
|
||||||
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
|
||||||
FROM tidal_albums_songs_old;
|
|
||||||
|
|
||||||
DROP TABLE tidal_albums_songs_old;
|
|
||||||
|
|
||||||
INSERT INTO tidal_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
|
||||||
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
|
||||||
FROM tidal_songs_old;
|
|
||||||
|
|
||||||
DROP TABLE tidal_songs_old;
|
|
||||||
|
|
||||||
INSERT INTO qobuz_artists_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
|
||||||
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
|
||||||
FROM qobuz_artists_songs_old;
|
|
||||||
|
|
||||||
DROP TABLE qobuz_artists_songs_old;
|
|
||||||
|
|
||||||
INSERT INTO qobuz_albums_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
|
||||||
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
|
||||||
FROM qobuz_albums_songs_old;
|
|
||||||
|
|
||||||
DROP TABLE qobuz_albums_songs_old;
|
|
||||||
|
|
||||||
INSERT INTO qobuz_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
|
||||||
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
|
||||||
FROM qobuz_songs_old;
|
|
||||||
|
|
||||||
DROP TABLE qobuz_songs_old;
|
|
||||||
|
|
||||||
INSERT INTO subsonic_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
|
||||||
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
|
||||||
FROM subsonic_songs_old;
|
|
||||||
|
|
||||||
DROP TABLE subsonic_songs_old;
|
|
||||||
|
|
||||||
INSERT INTO playlist_items (playlist, type, collection_id, playlist_url, title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
|
||||||
SELECT playlist, type, collection_id, url, title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
|
||||||
FROM playlist_items_old;
|
|
||||||
|
|
||||||
DROP TABLE playlist_items_old;
|
|
||||||
|
|
||||||
CREATE INDEX idx_url ON songs (url);
|
|
||||||
|
|
||||||
UPDATE schema_version SET version=8;
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
DROP TABLE %allsongstables_fts;
|
|
||||||
|
|
||||||
DROP TABLE playlist_items_fts_;
|
|
||||||
|
|
||||||
CREATE VIRTUAL TABLE %allsongstables_fts USING fts5(
|
|
||||||
|
|
||||||
ftstitle,
|
|
||||||
ftsalbum,
|
|
||||||
ftsartist,
|
|
||||||
ftsalbumartist,
|
|
||||||
ftscomposer,
|
|
||||||
ftsperformer,
|
|
||||||
ftsgrouping,
|
|
||||||
ftsgenre,
|
|
||||||
ftscomment,
|
|
||||||
tokenize = "unicode61 remove_diacritics 1"
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE VIRTUAL TABLE playlist_items_fts_ USING fts5(
|
|
||||||
|
|
||||||
ftstitle,
|
|
||||||
ftsalbum,
|
|
||||||
ftsartist,
|
|
||||||
ftsalbumartist,
|
|
||||||
ftscomposer,
|
|
||||||
ftsperformer,
|
|
||||||
ftsgrouping,
|
|
||||||
ftsgenre,
|
|
||||||
ftscomment,
|
|
||||||
tokenize = "unicode61 remove_diacritics 1"
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
INSERT INTO %allsongstables_fts (ROWID, ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment)
|
|
||||||
SELECT ROWID, title, album, artist, albumartist, composer, performer, grouping, genre, comment FROM %allsongstables;
|
|
||||||
|
|
||||||
INSERT INTO playlist_items_fts_ (ROWID, ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment)
|
|
||||||
SELECT ROWID, title, album, artist, albumartist, composer, performer, grouping, genre, comment FROM playlist_items;
|
|
||||||
|
|
||||||
UPDATE schema_version SET version=9;
|
|
||||||
@@ -7,37 +7,37 @@ DELETE FROM schema_version;
|
|||||||
INSERT INTO schema_version (version) VALUES (15);
|
INSERT INTO schema_version (version) VALUES (15);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS directories (
|
CREATE TABLE IF NOT EXISTS directories (
|
||||||
path TEXT NOT NULL DEFAULT '',
|
path TEXT NOT NULL,
|
||||||
subdirs INTEGER NOT NULL
|
subdirs INTEGER NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS subdirectories (
|
CREATE TABLE IF NOT EXISTS subdirectories (
|
||||||
directory_id INTEGER NOT NULL,
|
directory_id INTEGER NOT NULL,
|
||||||
path TEXT NOT NULL DEFAULT '',
|
path TEXT NOT NULL,
|
||||||
mtime INTEGER NOT NULL
|
mtime INTEGER NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS songs (
|
CREATE TABLE IF NOT EXISTS songs (
|
||||||
|
|
||||||
title TEXT DEFAULT '',
|
title TEXT,
|
||||||
album TEXT DEFAULT '',
|
album TEXT,
|
||||||
artist TEXT DEFAULT '',
|
artist TEXT,
|
||||||
albumartist TEXT DEFAULT '',
|
albumartist TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||||
genre TEXT DEFAULT '',
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT DEFAULT '',
|
composer TEXT,
|
||||||
performer TEXT DEFAULT '',
|
performer TEXT,
|
||||||
grouping TEXT DEFAULT '',
|
grouping TEXT,
|
||||||
comment TEXT DEFAULT '',
|
comment TEXT,
|
||||||
lyrics TEXT DEFAULT '',
|
lyrics TEXT,
|
||||||
|
|
||||||
artist_id TEXT DEFAULT '',
|
artist_id TEXT,
|
||||||
album_id TEXT DEFAULT '',
|
album_id TEXT,
|
||||||
song_id TEXT DEFAULT '',
|
song_id TEXT,
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
beginning INTEGER NOT NULL DEFAULT 0,
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
length INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -48,14 +48,14 @@ CREATE TABLE IF NOT EXISTS songs (
|
|||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
source INTEGER NOT NULL DEFAULT 0,
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||||
url TEXT NOT NULL DEFAULT '',
|
url TEXT NOT NULL,
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
filetype INTEGER NOT NULL DEFAULT 0,
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
filesize INTEGER NOT NULL DEFAULT -1,
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
mtime INTEGER NOT NULL DEFAULT -1,
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
ctime INTEGER NOT NULL DEFAULT -1,
|
||||||
unavailable INTEGER DEFAULT 0,
|
unavailable INTEGER DEFAULT 0,
|
||||||
|
|
||||||
fingerprint TEXT DEFAULT '',
|
fingerprint TEXT,
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
playcount INTEGER NOT NULL DEFAULT 0,
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -67,13 +67,13 @@ CREATE TABLE IF NOT EXISTS songs (
|
|||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
art_automatic TEXT DEFAULT '',
|
art_automatic TEXT,
|
||||||
art_manual TEXT DEFAULT '',
|
art_manual TEXT,
|
||||||
|
|
||||||
effective_albumartist TEXT DEFAULT '',
|
effective_albumartist TEXT,
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
cue_path TEXT DEFAULT '',
|
cue_path TEXT,
|
||||||
|
|
||||||
rating INTEGER DEFAULT -1
|
rating INTEGER DEFAULT -1
|
||||||
|
|
||||||
@@ -81,25 +81,25 @@ CREATE TABLE IF NOT EXISTS songs (
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS subsonic_songs (
|
CREATE TABLE IF NOT EXISTS subsonic_songs (
|
||||||
|
|
||||||
title TEXT DEFAULT '',
|
title TEXT,
|
||||||
album TEXT DEFAULT '',
|
album TEXT,
|
||||||
artist TEXT DEFAULT '',
|
artist TEXT,
|
||||||
albumartist TEXT DEFAULT '',
|
albumartist TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||||
genre TEXT DEFAULT '',
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT DEFAULT '',
|
composer TEXT,
|
||||||
performer TEXT DEFAULT '',
|
performer TEXT,
|
||||||
grouping TEXT DEFAULT '',
|
grouping TEXT,
|
||||||
comment TEXT DEFAULT '',
|
comment TEXT,
|
||||||
lyrics TEXT DEFAULT '',
|
lyrics TEXT,
|
||||||
|
|
||||||
artist_id TEXT DEFAULT '',
|
artist_id TEXT,
|
||||||
album_id TEXT DEFAULT '',
|
album_id TEXT,
|
||||||
song_id TEXT DEFAULT '',
|
song_id TEXT,
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
beginning INTEGER NOT NULL DEFAULT 0,
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
length INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -110,14 +110,14 @@ CREATE TABLE IF NOT EXISTS subsonic_songs (
|
|||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
source INTEGER NOT NULL DEFAULT 0,
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||||
url TEXT NOT NULL DEFAULT '',
|
url TEXT NOT NULL,
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
filetype INTEGER NOT NULL DEFAULT 0,
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
filesize INTEGER NOT NULL DEFAULT -1,
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
mtime INTEGER NOT NULL DEFAULT -1,
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
ctime INTEGER NOT NULL DEFAULT -1,
|
||||||
unavailable INTEGER DEFAULT 0,
|
unavailable INTEGER DEFAULT 0,
|
||||||
|
|
||||||
fingerprint TEXT DEFAULT '',
|
fingerprint TEXT,
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
playcount INTEGER NOT NULL DEFAULT 0,
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -129,13 +129,13 @@ CREATE TABLE IF NOT EXISTS subsonic_songs (
|
|||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
art_automatic TEXT DEFAULT '',
|
art_automatic TEXT,
|
||||||
art_manual TEXT DEFAULT '',
|
art_manual TEXT,
|
||||||
|
|
||||||
effective_albumartist TEXT DEFAULT '',
|
effective_albumartist TEXT,
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
cue_path TEXT DEFAULT '',
|
cue_path TEXT,
|
||||||
|
|
||||||
rating INTEGER DEFAULT -1
|
rating INTEGER DEFAULT -1
|
||||||
|
|
||||||
@@ -143,25 +143,25 @@ CREATE TABLE IF NOT EXISTS subsonic_songs (
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS tidal_artists_songs (
|
CREATE TABLE IF NOT EXISTS tidal_artists_songs (
|
||||||
|
|
||||||
title TEXT DEFAULT '',
|
title TEXT,
|
||||||
album TEXT DEFAULT '',
|
album TEXT,
|
||||||
artist TEXT DEFAULT '',
|
artist TEXT,
|
||||||
albumartist TEXT DEFAULT '',
|
albumartist TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||||
genre TEXT DEFAULT '',
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT DEFAULT '',
|
composer TEXT,
|
||||||
performer TEXT DEFAULT '',
|
performer TEXT,
|
||||||
grouping TEXT DEFAULT '',
|
grouping TEXT,
|
||||||
comment TEXT DEFAULT '',
|
comment TEXT,
|
||||||
lyrics TEXT DEFAULT '',
|
lyrics TEXT,
|
||||||
|
|
||||||
artist_id TEXT DEFAULT '',
|
artist_id TEXT,
|
||||||
album_id TEXT DEFAULT '',
|
album_id TEXT,
|
||||||
song_id TEXT DEFAULT '',
|
song_id TEXT,
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
beginning INTEGER NOT NULL DEFAULT 0,
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
length INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -172,14 +172,14 @@ CREATE TABLE IF NOT EXISTS tidal_artists_songs (
|
|||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
source INTEGER NOT NULL DEFAULT 0,
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||||
url TEXT NOT NULL DEFAULT '',
|
url TEXT NOT NULL,
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
filetype INTEGER NOT NULL DEFAULT 0,
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
filesize INTEGER NOT NULL DEFAULT -1,
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
mtime INTEGER NOT NULL DEFAULT -1,
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
ctime INTEGER NOT NULL DEFAULT -1,
|
||||||
unavailable INTEGER DEFAULT 0,
|
unavailable INTEGER DEFAULT 0,
|
||||||
|
|
||||||
fingerprint TEXT DEFAULT '',
|
fingerprint TEXT,
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
playcount INTEGER NOT NULL DEFAULT 0,
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -191,13 +191,13 @@ CREATE TABLE IF NOT EXISTS tidal_artists_songs (
|
|||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
art_automatic TEXT DEFAULT '',
|
art_automatic TEXT,
|
||||||
art_manual TEXT DEFAULT '',
|
art_manual TEXT,
|
||||||
|
|
||||||
effective_albumartist TEXT DEFAULT '',
|
effective_albumartist TEXT,
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
cue_path TEXT DEFAULT '',
|
cue_path TEXT,
|
||||||
|
|
||||||
rating INTEGER DEFAULT -1
|
rating INTEGER DEFAULT -1
|
||||||
|
|
||||||
@@ -205,25 +205,25 @@ CREATE TABLE IF NOT EXISTS tidal_artists_songs (
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS tidal_albums_songs (
|
CREATE TABLE IF NOT EXISTS tidal_albums_songs (
|
||||||
|
|
||||||
title TEXT DEFAULT '',
|
title TEXT,
|
||||||
album TEXT DEFAULT '',
|
album TEXT,
|
||||||
artist TEXT DEFAULT '',
|
artist TEXT,
|
||||||
albumartist TEXT DEFAULT '',
|
albumartist TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||||
genre TEXT DEFAULT '',
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT DEFAULT '',
|
composer TEXT,
|
||||||
performer TEXT DEFAULT '',
|
performer TEXT,
|
||||||
grouping TEXT DEFAULT '',
|
grouping TEXT,
|
||||||
comment TEXT DEFAULT '',
|
comment TEXT,
|
||||||
lyrics TEXT DEFAULT '',
|
lyrics TEXT,
|
||||||
|
|
||||||
artist_id TEXT DEFAULT '',
|
artist_id TEXT,
|
||||||
album_id TEXT DEFAULT '',
|
album_id TEXT,
|
||||||
song_id TEXT DEFAULT '',
|
song_id TEXT,
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
beginning INTEGER NOT NULL DEFAULT 0,
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
length INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -234,14 +234,14 @@ CREATE TABLE IF NOT EXISTS tidal_albums_songs (
|
|||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
source INTEGER NOT NULL DEFAULT 0,
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||||
url TEXT NOT NULL DEFAULT '',
|
url TEXT NOT NULL,
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
filetype INTEGER NOT NULL DEFAULT 0,
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
filesize INTEGER NOT NULL DEFAULT -1,
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
mtime INTEGER NOT NULL DEFAULT -1,
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
ctime INTEGER NOT NULL DEFAULT -1,
|
||||||
unavailable INTEGER DEFAULT 0,
|
unavailable INTEGER DEFAULT 0,
|
||||||
|
|
||||||
fingerprint TEXT DEFAULT '',
|
fingerprint TEXT,
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
playcount INTEGER NOT NULL DEFAULT 0,
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -253,13 +253,13 @@ CREATE TABLE IF NOT EXISTS tidal_albums_songs (
|
|||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
art_automatic TEXT DEFAULT '',
|
art_automatic TEXT,
|
||||||
art_manual TEXT DEFAULT '',
|
art_manual TEXT,
|
||||||
|
|
||||||
effective_albumartist TEXT DEFAULT '',
|
effective_albumartist TEXT,
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
cue_path TEXT DEFAULT '',
|
cue_path TEXT,
|
||||||
|
|
||||||
rating INTEGER DEFAULT -1
|
rating INTEGER DEFAULT -1
|
||||||
|
|
||||||
@@ -267,25 +267,25 @@ CREATE TABLE IF NOT EXISTS tidal_albums_songs (
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS tidal_songs (
|
CREATE TABLE IF NOT EXISTS tidal_songs (
|
||||||
|
|
||||||
title TEXT DEFAULT '',
|
title TEXT,
|
||||||
album TEXT DEFAULT '',
|
album TEXT,
|
||||||
artist TEXT DEFAULT '',
|
artist TEXT,
|
||||||
albumartist TEXT DEFAULT '',
|
albumartist TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||||
genre TEXT DEFAULT '',
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT DEFAULT '',
|
composer TEXT,
|
||||||
performer TEXT DEFAULT '',
|
performer TEXT,
|
||||||
grouping TEXT DEFAULT '',
|
grouping TEXT,
|
||||||
comment TEXT DEFAULT '',
|
comment TEXT,
|
||||||
lyrics TEXT DEFAULT '',
|
lyrics TEXT,
|
||||||
|
|
||||||
artist_id TEXT DEFAULT '',
|
artist_id TEXT,
|
||||||
album_id TEXT DEFAULT '',
|
album_id TEXT,
|
||||||
song_id TEXT DEFAULT '',
|
song_id TEXT,
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
beginning INTEGER NOT NULL DEFAULT 0,
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
length INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -296,14 +296,14 @@ CREATE TABLE IF NOT EXISTS tidal_songs (
|
|||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
source INTEGER NOT NULL DEFAULT 0,
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||||
url TEXT NOT NULL DEFAULT '',
|
url TEXT NOT NULL,
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
filetype INTEGER NOT NULL DEFAULT 0,
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
filesize INTEGER NOT NULL DEFAULT -1,
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
mtime INTEGER NOT NULL DEFAULT -1,
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
ctime INTEGER NOT NULL DEFAULT -1,
|
||||||
unavailable INTEGER DEFAULT 0,
|
unavailable INTEGER DEFAULT 0,
|
||||||
|
|
||||||
fingerprint TEXT DEFAULT '',
|
fingerprint TEXT,
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
playcount INTEGER NOT NULL DEFAULT 0,
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -315,13 +315,13 @@ CREATE TABLE IF NOT EXISTS tidal_songs (
|
|||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
art_automatic TEXT DEFAULT '',
|
art_automatic TEXT,
|
||||||
art_manual TEXT DEFAULT '',
|
art_manual TEXT,
|
||||||
|
|
||||||
effective_albumartist TEXT DEFAULT '',
|
effective_albumartist TEXT,
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
cue_path TEXT DEFAULT '',
|
cue_path TEXT,
|
||||||
|
|
||||||
rating INTEGER DEFAULT -1
|
rating INTEGER DEFAULT -1
|
||||||
|
|
||||||
@@ -329,25 +329,25 @@ CREATE TABLE IF NOT EXISTS tidal_songs (
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
|
CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
|
||||||
|
|
||||||
title TEXT DEFAULT '',
|
title TEXT,
|
||||||
album TEXT DEFAULT '',
|
album TEXT,
|
||||||
artist TEXT DEFAULT '',
|
artist TEXT,
|
||||||
albumartist TEXT DEFAULT '',
|
albumartist TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||||
genre TEXT DEFAULT '',
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT DEFAULT '',
|
composer TEXT,
|
||||||
performer TEXT DEFAULT '',
|
performer TEXT,
|
||||||
grouping TEXT DEFAULT '',
|
grouping TEXT,
|
||||||
comment TEXT DEFAULT '',
|
comment TEXT,
|
||||||
lyrics TEXT DEFAULT '',
|
lyrics TEXT,
|
||||||
|
|
||||||
artist_id TEXT DEFAULT '',
|
artist_id TEXT,
|
||||||
album_id TEXT DEFAULT '',
|
album_id TEXT,
|
||||||
song_id TEXT DEFAULT '',
|
song_id TEXT,
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
beginning INTEGER NOT NULL DEFAULT 0,
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
length INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -358,14 +358,14 @@ CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
|
|||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
source INTEGER NOT NULL DEFAULT 0,
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||||
url TEXT NOT NULL DEFAULT '',
|
url TEXT NOT NULL,
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
filetype INTEGER NOT NULL DEFAULT 0,
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
filesize INTEGER NOT NULL DEFAULT -1,
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
mtime INTEGER NOT NULL DEFAULT -1,
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
ctime INTEGER NOT NULL DEFAULT -1,
|
||||||
unavailable INTEGER DEFAULT 0,
|
unavailable INTEGER DEFAULT 0,
|
||||||
|
|
||||||
fingerprint TEXT DEFAULT '',
|
fingerprint TEXT,
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
playcount INTEGER NOT NULL DEFAULT 0,
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -377,13 +377,13 @@ CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
|
|||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
art_automatic TEXT DEFAULT '',
|
art_automatic TEXT,
|
||||||
art_manual TEXT DEFAULT '',
|
art_manual TEXT,
|
||||||
|
|
||||||
effective_albumartist TEXT DEFAULT '',
|
effective_albumartist TEXT,
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
cue_path TEXT DEFAULT '',
|
cue_path TEXT,
|
||||||
|
|
||||||
rating INTEGER DEFAULT -1
|
rating INTEGER DEFAULT -1
|
||||||
|
|
||||||
@@ -391,25 +391,25 @@ CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
|
CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
|
||||||
|
|
||||||
title TEXT DEFAULT '',
|
title TEXT,
|
||||||
album TEXT DEFAULT '',
|
album TEXT,
|
||||||
artist TEXT DEFAULT '',
|
artist TEXT,
|
||||||
albumartist TEXT DEFAULT '',
|
albumartist TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||||
genre TEXT DEFAULT '',
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT DEFAULT '',
|
composer TEXT,
|
||||||
performer TEXT DEFAULT '',
|
performer TEXT,
|
||||||
grouping TEXT DEFAULT '',
|
grouping TEXT,
|
||||||
comment TEXT DEFAULT '',
|
comment TEXT,
|
||||||
lyrics TEXT DEFAULT '',
|
lyrics TEXT,
|
||||||
|
|
||||||
artist_id TEXT DEFAULT '',
|
artist_id TEXT,
|
||||||
album_id TEXT DEFAULT '',
|
album_id TEXT,
|
||||||
song_id TEXT DEFAULT '',
|
song_id TEXT,
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
beginning INTEGER NOT NULL DEFAULT 0,
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
length INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -420,14 +420,14 @@ CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
|
|||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
source INTEGER NOT NULL DEFAULT 0,
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||||
url TEXT NOT NULL DEFAULT '',
|
url TEXT NOT NULL,
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
filetype INTEGER NOT NULL DEFAULT 0,
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
filesize INTEGER NOT NULL DEFAULT -1,
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
mtime INTEGER NOT NULL DEFAULT -1,
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
ctime INTEGER NOT NULL DEFAULT -1,
|
||||||
unavailable INTEGER DEFAULT 0,
|
unavailable INTEGER DEFAULT 0,
|
||||||
|
|
||||||
fingerprint TEXT DEFAULT '',
|
fingerprint TEXT,
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
playcount INTEGER NOT NULL DEFAULT 0,
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -439,13 +439,13 @@ CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
|
|||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
art_automatic TEXT DEFAULT '',
|
art_automatic TEXT,
|
||||||
art_manual TEXT DEFAULT '',
|
art_manual TEXT,
|
||||||
|
|
||||||
effective_albumartist TEXT DEFAULT '',
|
effective_albumartist TEXT,
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
cue_path TEXT DEFAULT '',
|
cue_path TEXT,
|
||||||
|
|
||||||
rating INTEGER DEFAULT -1
|
rating INTEGER DEFAULT -1
|
||||||
|
|
||||||
@@ -453,25 +453,25 @@ CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS qobuz_songs (
|
CREATE TABLE IF NOT EXISTS qobuz_songs (
|
||||||
|
|
||||||
title TEXT DEFAULT '',
|
title TEXT,
|
||||||
album TEXT DEFAULT '',
|
album TEXT,
|
||||||
artist TEXT DEFAULT '',
|
artist TEXT,
|
||||||
albumartist TEXT DEFAULT '',
|
albumartist TEXT,
|
||||||
track INTEGER NOT NULL DEFAULT -1,
|
track INTEGER NOT NULL DEFAULT -1,
|
||||||
disc INTEGER NOT NULL DEFAULT -1,
|
disc INTEGER NOT NULL DEFAULT -1,
|
||||||
year INTEGER NOT NULL DEFAULT -1,
|
year INTEGER NOT NULL DEFAULT -1,
|
||||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||||
genre TEXT DEFAULT '',
|
genre TEXT,
|
||||||
compilation INTEGER NOT NULL DEFAULT 0,
|
compilation INTEGER NOT NULL DEFAULT 0,
|
||||||
composer TEXT DEFAULT '',
|
composer TEXT,
|
||||||
performer TEXT DEFAULT '',
|
performer TEXT,
|
||||||
grouping TEXT DEFAULT '',
|
grouping TEXT,
|
||||||
comment TEXT DEFAULT '',
|
comment TEXT,
|
||||||
lyrics TEXT DEFAULT '',
|
lyrics TEXT,
|
||||||
|
|
||||||
artist_id TEXT DEFAULT '',
|
artist_id TEXT,
|
||||||
album_id TEXT DEFAULT '',
|
album_id TEXT,
|
||||||
song_id TEXT DEFAULT '',
|
song_id TEXT,
|
||||||
|
|
||||||
beginning INTEGER NOT NULL DEFAULT 0,
|
beginning INTEGER NOT NULL DEFAULT 0,
|
||||||
length INTEGER NOT NULL DEFAULT 0,
|
length INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -482,14 +482,14 @@ CREATE TABLE IF NOT EXISTS qobuz_songs (
|
|||||||
|
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
source INTEGER NOT NULL DEFAULT 0,
|
||||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||||
url TEXT NOT NULL DEFAULT '',
|
url TEXT NOT NULL,
|
||||||
filetype INTEGER NOT NULL DEFAULT 0,
|
filetype INTEGER NOT NULL DEFAULT 0,
|
||||||
filesize INTEGER NOT NULL DEFAULT -1,
|
filesize INTEGER NOT NULL DEFAULT -1,
|
||||||
mtime INTEGER NOT NULL DEFAULT -1,
|
mtime INTEGER NOT NULL DEFAULT -1,
|
||||||
ctime INTEGER NOT NULL DEFAULT -1,
|
ctime INTEGER NOT NULL DEFAULT -1,
|
||||||
unavailable INTEGER DEFAULT 0,
|
unavailable INTEGER DEFAULT 0,
|
||||||
|
|
||||||
fingerprint TEXT DEFAULT '',
|
fingerprint TEXT,
|
||||||
|
|
||||||
playcount INTEGER NOT NULL DEFAULT 0,
|
playcount INTEGER NOT NULL DEFAULT 0,
|
||||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -501,13 +501,13 @@ CREATE TABLE IF NOT EXISTS qobuz_songs (
|
|||||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
art_automatic TEXT DEFAULT '',
|
art_automatic TEXT,
|
||||||
art_manual TEXT DEFAULT '',
|
art_manual TEXT,
|
||||||
|
|
||||||
effective_albumartist TEXT DEFAULT '',
|
effective_albumartist TEXT,
|
||||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
cue_path TEXT DEFAULT '',
|
cue_path TEXT,
|
||||||
|
|
||||||
rating INTEGER DEFAULT -1
|
rating INTEGER DEFAULT -1
|
||||||
|
|
||||||
@@ -515,15 +515,15 @@ CREATE TABLE IF NOT EXISTS qobuz_songs (
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS playlists (
|
CREATE TABLE IF NOT EXISTS playlists (
|
||||||
|
|
||||||
name TEXT NOT NULL DEFAULT '',
|
name TEXT NOT NULL,
|
||||||
last_played INTEGER NOT NULL DEFAULT -1,
|
last_played INTEGER NOT NULL DEFAULT -1,
|
||||||
ui_order INTEGER NOT NULL DEFAULT 0,
|
ui_order INTEGER NOT NULL DEFAULT 0,
|
||||||
special_type TEXT DEFAULT '',
|
special_type TEXT,
|
||||||
ui_path TEXT DEFAULT '',
|
ui_path TEXT,
|
||||||
is_favorite INTEGER NOT NULL DEFAULT 0,
|
is_favorite INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
dynamic_playlist_type INTEGER,
|
dynamic_playlist_type INTEGER,
|
||||||
dynamic_playlist_backend TEXT DEFAULT '',
|
dynamic_playlist_backend TEXT,
|
||||||
dynamic_playlist_data BLOB
|
dynamic_playlist_data BLOB
|
||||||
|
|
||||||
);
|
);
|
||||||
@@ -533,27 +533,27 @@ CREATE TABLE IF NOT EXISTS playlist_items (
|
|||||||
playlist INTEGER NOT NULL,
|
playlist INTEGER NOT NULL,
|
||||||
type INTEGER NOT NULL DEFAULT 0,
|
type INTEGER NOT NULL DEFAULT 0,
|
||||||
collection_id INTEGER,
|
collection_id INTEGER,
|
||||||
playlist_url TEXT DEFAULT '',
|
playlist_url TEXT,
|
||||||
|
|
||||||
title TEXT DEFAULT '',
|
title TEXT,
|
||||||
album TEXT DEFAULT '',
|
album TEXT,
|
||||||
artist TEXT DEFAULT '',
|
artist TEXT,
|
||||||
albumartist TEXT DEFAULT '',
|
albumartist TEXT,
|
||||||
track INTEGER,
|
track INTEGER,
|
||||||
disc INTEGER,
|
disc INTEGER,
|
||||||
year INTEGER,
|
year INTEGER,
|
||||||
originalyear INTEGER,
|
originalyear INTEGER,
|
||||||
genre TEXT DEFAULT '',
|
genre TEXT,
|
||||||
compilation INTEGER DEFAULT 0,
|
compilation INTEGER DEFAULT 0,
|
||||||
composer TEXT DEFAULT '',
|
composer TEXT,
|
||||||
performer TEXT DEFAULT '',
|
performer TEXT,
|
||||||
grouping TEXT DEFAULT '',
|
grouping TEXT,
|
||||||
comment TEXT DEFAULT '',
|
comment TEXT,
|
||||||
lyrics TEXT DEFAULT '',
|
lyrics TEXT,
|
||||||
|
|
||||||
artist_id TEXT DEFAULT '',
|
artist_id TEXT,
|
||||||
album_id TEXT DEFAULT '',
|
album_id TEXT,
|
||||||
song_id TEXT DEFAULT '',
|
song_id TEXT,
|
||||||
|
|
||||||
beginning INTEGER,
|
beginning INTEGER,
|
||||||
length INTEGER,
|
length INTEGER,
|
||||||
@@ -564,14 +564,14 @@ CREATE TABLE IF NOT EXISTS playlist_items (
|
|||||||
|
|
||||||
source INTEGER,
|
source INTEGER,
|
||||||
directory_id INTEGER,
|
directory_id INTEGER,
|
||||||
url TEXT DEFAULT '',
|
url TEXT NOT NULL,
|
||||||
filetype INTEGER,
|
filetype INTEGER,
|
||||||
filesize INTEGER,
|
filesize INTEGER,
|
||||||
mtime INTEGER,
|
mtime INTEGER,
|
||||||
ctime INTEGER,
|
ctime INTEGER,
|
||||||
unavailable INTEGER DEFAULT 0,
|
unavailable INTEGER DEFAULT 0,
|
||||||
|
|
||||||
fingerprint TEXT DEFAULT '',
|
fingerprint TEXT,
|
||||||
|
|
||||||
playcount INTEGER DEFAULT 0,
|
playcount INTEGER DEFAULT 0,
|
||||||
skipcount INTEGER DEFAULT 0,
|
skipcount INTEGER DEFAULT 0,
|
||||||
@@ -583,23 +583,23 @@ CREATE TABLE IF NOT EXISTS playlist_items (
|
|||||||
compilation_off INTEGER DEFAULT 0,
|
compilation_off INTEGER DEFAULT 0,
|
||||||
compilation_effective INTEGER DEFAULT 0,
|
compilation_effective INTEGER DEFAULT 0,
|
||||||
|
|
||||||
art_automatic TEXT DEFAULT '',
|
art_automatic TEXT,
|
||||||
art_manual TEXT DEFAULT '',
|
art_manual TEXT,
|
||||||
|
|
||||||
effective_albumartist TEXT DEFAULT '',
|
effective_albumartist TEXT,
|
||||||
effective_originalyear INTEGER,
|
effective_originalyear INTEGER,
|
||||||
|
|
||||||
cue_path TEXT DEFAULT '',
|
cue_path TEXT,
|
||||||
|
|
||||||
rating INTEGER DEFAULT -1
|
rating INTEGER DEFAULT -1
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS devices (
|
CREATE TABLE IF NOT EXISTS devices (
|
||||||
unique_id TEXT NOT NULL DEFAULT '',
|
unique_id TEXT NOT NULL,
|
||||||
friendly_name TEXT DEFAULT '',
|
friendly_name TEXT,
|
||||||
size INTEGER,
|
size INTEGER,
|
||||||
icon TEXT DEFAULT '',
|
icon TEXT,
|
||||||
schema_version INTEGER NOT NULL DEFAULT 0,
|
schema_version INTEGER NOT NULL DEFAULT 0,
|
||||||
transcode_mode NOT NULL DEFAULT 3,
|
transcode_mode NOT NULL DEFAULT 3,
|
||||||
transcode_format NOT NULL DEFAULT 5
|
transcode_format NOT NULL DEFAULT 5
|
||||||
@@ -607,9 +607,9 @@ CREATE TABLE IF NOT EXISTS devices (
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS radio_channels (
|
CREATE TABLE IF NOT EXISTS radio_channels (
|
||||||
source INTEGER NOT NULL DEFAULT 0,
|
source INTEGER NOT NULL DEFAULT 0,
|
||||||
name TEXT DEFAULT '',
|
name TEXT,
|
||||||
url TEXT DEFAULT '',
|
url TEXT NOT NULL,
|
||||||
thumbnail_url TEXT DEFAULT ''
|
thumbnail_url TEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_url ON songs (url);
|
CREATE INDEX IF NOT EXISTS idx_url ON songs (url);
|
||||||
|
|||||||
@@ -31,6 +31,10 @@
|
|||||||
background-color: %palette-base;
|
background-color: %palette-base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#context-scrollarea {
|
||||||
|
background-color: %palette-base;
|
||||||
|
}
|
||||||
|
|
||||||
QToolButton {
|
QToolButton {
|
||||||
border: 2px solid transparent;
|
border: 2px solid transparent;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
|||||||
22
debian/CMakeLists.txt
vendored
Normal file
22
debian/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
if(LSB_RELEASE_EXEC AND DPKG_BUILDPACKAGE)
|
||||||
|
|
||||||
|
execute_process(COMMAND env LC_ALL=C date "+%a, %-d %b %Y %H:%M:%S %z" OUTPUT_VARIABLE DEB_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -cs" OUTPUT_VARIABLE DEB_CODENAME OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
|
||||||
|
if(DEB_CODENAME AND DEB_DATE)
|
||||||
|
|
||||||
|
if(BUILD_WITH_QT5)
|
||||||
|
set(DEBIAN_BUILD_DEPENDS_QT_PACKAGES qtbase5-dev,qtbase5-dev-tools,qttools5-dev,qttools5-dev-tools,libqt5x11extras5-dev)
|
||||||
|
set(DEBIAN_DEPENDS_QT_PACKAGES libqt5sql5-sqlite)
|
||||||
|
endif()
|
||||||
|
if(BUILD_WITH_QT6)
|
||||||
|
set(DEBIAN_BUILD_DEPENDS_QT_PACKAGES qt6-base-dev,qt6-base-dev-tools,qt6-tools-dev,qt6-tools-dev-tools,qt6-l10n-tools)
|
||||||
|
set(DEBIAN_DEPENDS_QT_PACKAGES libqt6sql6-sqlite,qt6-qpa-plugins)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/control.in ${CMAKE_CURRENT_SOURCE_DIR}/control @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/changelog.in ${CMAKE_CURRENT_SOURCE_DIR}/changelog)
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endif()
|
||||||
20
debian/control → debian/control.in
vendored
20
debian/control → debian/control.in
vendored
@@ -6,6 +6,7 @@ Build-Depends: debhelper (>= 11),
|
|||||||
make,
|
make,
|
||||||
cmake,
|
cmake,
|
||||||
gcc,
|
gcc,
|
||||||
|
g++,
|
||||||
protobuf-compiler,
|
protobuf-compiler,
|
||||||
libglib2.0-dev,
|
libglib2.0-dev,
|
||||||
libdbus-1-dev,
|
libdbus-1-dev,
|
||||||
@@ -16,11 +17,8 @@ Build-Depends: debhelper (>= 11),
|
|||||||
libasound2-dev,
|
libasound2-dev,
|
||||||
libpulse-dev,
|
libpulse-dev,
|
||||||
libtag1-dev,
|
libtag1-dev,
|
||||||
qtbase5-dev,
|
libicu-dev,
|
||||||
qtbase5-private-dev,
|
@DEBIAN_BUILD_DEPENDS_QT_PACKAGES@,
|
||||||
qtbase5-dev-tools,
|
|
||||||
qttools5-dev,
|
|
||||||
libqt5x11extras5-dev,
|
|
||||||
libgstreamer1.0-dev,
|
libgstreamer1.0-dev,
|
||||||
libgstreamer-plugins-base1.0-dev,
|
libgstreamer-plugins-base1.0-dev,
|
||||||
libcdio-dev,
|
libcdio-dev,
|
||||||
@@ -28,20 +26,19 @@ Build-Depends: debhelper (>= 11),
|
|||||||
libmtp-dev,
|
libmtp-dev,
|
||||||
libchromaprint-dev,
|
libchromaprint-dev,
|
||||||
libfftw3-dev
|
libfftw3-dev
|
||||||
Standards-Version: 4.2.1
|
Standards-Version: 4.6.1
|
||||||
|
|
||||||
Package: strawberry
|
Package: strawberry
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends},
|
Depends: ${shlibs:Depends},
|
||||||
${misc:Depends},
|
${misc:Depends},
|
||||||
libsqlite3-0,
|
@DEBIAN_DEPENDS_QT_PACKAGES@,
|
||||||
libqt5sql5-sqlite,
|
|
||||||
gstreamer1.0-plugins-base,
|
gstreamer1.0-plugins-base,
|
||||||
gstreamer1.0-plugins-good,
|
gstreamer1.0-plugins-good,
|
||||||
gstreamer1.0-alsa,
|
gstreamer1.0-alsa,
|
||||||
gstreamer1.0-pulseaudio
|
gstreamer1.0-pulseaudio
|
||||||
Homepage: http://www.strawberrymusicplayer.org/
|
Homepage: http://www.strawberrymusicplayer.org/
|
||||||
Description: Audio player and music collection organizer
|
Description: music player and music collection organizer
|
||||||
Strawberry is a music player aimed at music collectors and audiophiles.
|
Strawberry is a music player aimed at music collectors and audiophiles.
|
||||||
.
|
.
|
||||||
Features:
|
Features:
|
||||||
@@ -49,14 +46,13 @@ Description: Audio player and music collection organizer
|
|||||||
- Supports WAV, FLAC, WavPack, Ogg Vorbis, Speex, MPC, TrueAudio, AIFF, MP4, MP3 and ASF
|
- Supports WAV, FLAC, WavPack, Ogg Vorbis, Speex, MPC, TrueAudio, AIFF, MP4, MP3 and ASF
|
||||||
- Audio CD playback
|
- Audio CD playback
|
||||||
- Native desktop notifications
|
- Native desktop notifications
|
||||||
- Playlist management
|
- Playlist management and playlists in multiple formats
|
||||||
- Playlists in multiple formats
|
- Smart and dynamic playlists
|
||||||
- Advanced audio output and device configuration for bit-perfect playback on Linux
|
- Advanced audio output and device configuration for bit-perfect playback on Linux
|
||||||
- Edit tags on audio files
|
- Edit tags on audio files
|
||||||
- Automatically retrieve tags from MusicBrainz
|
- Automatically retrieve tags from MusicBrainz
|
||||||
- Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify
|
- Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify
|
||||||
- Song lyrics from AudD, Genius, Musixmatch, ChartLyrics, lyrics.ovh and lololyrics.com
|
- Song lyrics from AudD, Genius, Musixmatch, ChartLyrics, lyrics.ovh and lololyrics.com
|
||||||
- Support for multiple backends
|
|
||||||
- Audio analyzer
|
- Audio analyzer
|
||||||
- Audio equalizer
|
- Audio equalizer
|
||||||
- Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
|
- Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
|
||||||
56
debian/copyright
vendored
56
debian/copyright
vendored
@@ -5,10 +5,10 @@ Source: https://github.com/strawberrymusicplayer/strawberry
|
|||||||
|
|
||||||
Files: *
|
Files: *
|
||||||
Copyright: 2010-2015, David Sansome <me@davidsansome.com>
|
Copyright: 2010-2015, David Sansome <me@davidsansome.com>
|
||||||
2012-2014, 2017-2022 Jonas Kvinge <jonas@jkvinge.net>
|
2012-2014, 2017-2023 Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/core/timeconstants.h
|
Files: src/utilities/timeconstants.h
|
||||||
ext/libstrawberry-common/core/logging.cpp
|
ext/libstrawberry-common/core/logging.cpp
|
||||||
ext/libstrawberry-common/core/logging.h
|
ext/libstrawberry-common/core/logging.h
|
||||||
ext/libstrawberry-common/core/messagehandler.cpp
|
ext/libstrawberry-common/core/messagehandler.cpp
|
||||||
@@ -81,7 +81,7 @@ Files: src/core/main.h
|
|||||||
src/globalshortcuts/globalshortcutsbackend-win.h
|
src/globalshortcuts/globalshortcutsbackend-win.h
|
||||||
src/globalshortcuts/globalshortcut.cpp
|
src/globalshortcuts/globalshortcut.cpp
|
||||||
src/globalshortcuts/globalshortcut.h
|
src/globalshortcuts/globalshortcut.h
|
||||||
src/globalshortcuts/globalshortcut-X11.cpp
|
src/globalshortcuts/globalshortcut-x11.cpp
|
||||||
src/globalshortcuts/globalshortcut-win.cpp
|
src/globalshortcuts/globalshortcut-win.cpp
|
||||||
src/globalshortcuts/keymapper_x11.h
|
src/globalshortcuts/keymapper_x11.h
|
||||||
src/globalshortcuts/keymapper_win.h
|
src/globalshortcuts/keymapper_win.h
|
||||||
@@ -96,12 +96,14 @@ Files: src/core/main.h
|
|||||||
ext/libstrawberry-tagreader/tagreadertagparser.cpp
|
ext/libstrawberry-tagreader/tagreadertagparser.cpp
|
||||||
ext/libstrawberry-tagreader/tagreadertagparser.h
|
ext/libstrawberry-tagreader/tagreadertagparser.h
|
||||||
ext/macdeploycheck/*
|
ext/macdeploycheck/*
|
||||||
Copyright: 2012-2014, 2017-2022, Jonas Kvinge <jonas@jkvinge.net>
|
src/widgets/resizabletextedit.cpp
|
||||||
|
src/widgets/resizabletextedit.h
|
||||||
|
Copyright: 2012-2014, 2017-2023, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/engine/enginebase.cpp
|
Files: src/engine/enginebase.cpp
|
||||||
src/engine/enginebase.h
|
src/engine/enginebase.h
|
||||||
Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
|
Copyright: 2017-2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
2010, David Sansome <me@davidsansome.com>
|
2010, David Sansome <me@davidsansome.com>
|
||||||
2004, 2005, Max Howell, <max.howell@methylblue.com>
|
2004, 2005, Max Howell, <max.howell@methylblue.com>
|
||||||
2003, Mark Kretschmann <markey@web.de>
|
2003, Mark Kretschmann <markey@web.de>
|
||||||
@@ -109,7 +111,7 @@ License: GPL-3+
|
|||||||
|
|
||||||
Files: src/engine/gstengine.cpp
|
Files: src/engine/gstengine.cpp
|
||||||
src/engine/gstengine.h
|
src/engine/gstengine.h
|
||||||
Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
|
Copyright: 2017-2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
2006, Paul Cifarelli <paul@cifarelli.net>
|
2006, Paul Cifarelli <paul@cifarelli.net>
|
||||||
2005, Jakub Stachowski <qbast@go2.pl>
|
2005, Jakub Stachowski <qbast@go2.pl>
|
||||||
2003-2005, Mark Kretschmann <markey@web.de>
|
2003-2005, Mark Kretschmann <markey@web.de>
|
||||||
@@ -125,12 +127,7 @@ Files: src/core/application.cpp
|
|||||||
src/core/application.h
|
src/core/application.h
|
||||||
Copyright: 2012, David Sansome <me@davidsansome.com>
|
Copyright: 2012, David Sansome <me@davidsansome.com>
|
||||||
2012, 2014, John Maguire <john.maguire@gmail.com>
|
2012, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
2018, Jonas Kvinge <jonas@jkvinge.net>
|
2018-2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: GPL-3+
|
|
||||||
|
|
||||||
Files: src/core/appearance.cpp
|
|
||||||
src/core/appearance.h
|
|
||||||
Copyright: 2012, Arnaud Bienner <arnaud.bienner@gmail.com>
|
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/covermanager/discogscoverprovider.cpp
|
Files: src/covermanager/discogscoverprovider.cpp
|
||||||
@@ -139,13 +136,7 @@ Copyright: 2012, Martin Björklund <mbj4668@gmail.com>
|
|||||||
2016, Jonas Kvinge <jonas@jkvinge.net>
|
2016, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: ext/libstrawberry-common/core/arraysize.h
|
Files: src/core/lazy.h
|
||||||
ext/libstrawberry-common/core/scoped_nsautorelease_pool.h
|
|
||||||
ext/libstrawberry-common/core/scoped_nsautorelease_pool.mm
|
|
||||||
Copyright: 2010, 2011, 2014, The Chromium Authors.
|
|
||||||
License: BSD-style
|
|
||||||
|
|
||||||
Files: ext/libstrawberry-common/core/lazy.h
|
|
||||||
Copyright: 2016, John Maguire <john.maguire@gmail.com>
|
Copyright: 2016, John Maguire <john.maguire@gmail.com>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
@@ -193,12 +184,16 @@ Copyright: 2011, Tyler Rhodes <tyler.s.rhodes@gmail.com>
|
|||||||
2015, Arun Narayanankutty <n.arun.lifescience@gmail.com>
|
2015, Arun Narayanankutty <n.arun.lifescience@gmail.com>
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
|
|
||||||
Files: src/collection/savedgroupingmanager.h
|
Files: src/collection/savedgroupingmanager.*
|
||||||
Copyright: 2015, Nick Lanham <nick@afternight.org>
|
Copyright: 2015, Nick Lanham <nick@afternight.org>
|
||||||
|
2019-2021 Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/core/scoped_cftyperef.h
|
Files: src/core/arraysize.h
|
||||||
|
src/core/scoped_cftyperef.h
|
||||||
src/core/scoped_nsobject.h
|
src/core/scoped_nsobject.h
|
||||||
|
src/core/scoped_nsautorelease_pool.h
|
||||||
|
src/core/scoped_nsautorelease_pool.mm
|
||||||
Copyright: 2010, 2011, 2014, The Chromium Authors.
|
Copyright: 2010, 2011, 2014, The Chromium Authors.
|
||||||
License: BSD-style
|
License: BSD-style
|
||||||
|
|
||||||
@@ -217,7 +212,7 @@ Files: src/internet/localredirectserver.cpp
|
|||||||
src/internet/localredirectserver.h
|
src/internet/localredirectserver.h
|
||||||
Copyright: 2012, 2014, John Maguire <john.maguire@gmail.com>
|
Copyright: 2012, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||||
2018-2019, Jonas Kvinge <jonas@jkvinge.net>
|
2018-2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/transcoder/transcoderoptionsopus.cpp
|
Files: src/transcoder/transcoderoptionsopus.cpp
|
||||||
@@ -232,12 +227,22 @@ Files: src/widgets/clickablelabel.cpp
|
|||||||
Copyright: 2010, 2011, Andrea Decorte <adecorte@gmail.com>
|
Copyright: 2010, 2011, Andrea Decorte <adecorte@gmail.com>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/widgets/sliderwidget.cpp
|
Files: src/widgets/sliderslider.cpp
|
||||||
src/widgets/sliderwidget.h
|
src/widgets/sliderslider.h
|
||||||
Copyright: 2005, Gábor Lehel
|
src/widgets/prettyslider.cpp
|
||||||
|
src/widgets/prettyslider.h
|
||||||
|
src/widgets/volumeslider.cpp
|
||||||
|
src/widgets/volumeslider.h
|
||||||
|
Copyright: 2018-2023, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
|
2005, Gábor Lehel
|
||||||
2003, Mark Kretschmann <markey@web.de>
|
2003, Mark Kretschmann <markey@web.de>
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
|
|
||||||
|
Files: src/scrobbler/subsonicscrobbler.*
|
||||||
|
Copyright: 2018-2021 Jonas Kvinge <jonas@jkvinge.net>
|
||||||
|
2020 Pascal Below <spezifisch@below.fr>
|
||||||
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/core/stylehelper.cpp
|
Files: src/core/stylehelper.cpp
|
||||||
src/core/stylehelper.h
|
src/core/stylehelper.h
|
||||||
Copyright: 2016 The Qt Company Ltd.
|
Copyright: 2016 The Qt Company Ltd.
|
||||||
@@ -253,6 +258,7 @@ License: GPL-2+
|
|||||||
Files: src/widgets/qsearchfield_nonmac.cpp
|
Files: src/widgets/qsearchfield_nonmac.cpp
|
||||||
src/widgets/qsearchfield_mac.mm
|
src/widgets/qsearchfield_mac.mm
|
||||||
src/widgets/qsearchfield.h
|
src/widgets/qsearchfield.h
|
||||||
|
src/widgets/qocoa_mac.h
|
||||||
Copyright: 2011, Mike McQuaid <mike@mikemcquaid.com>
|
Copyright: 2011, Mike McQuaid <mike@mikemcquaid.com>
|
||||||
License: Expat
|
License: Expat
|
||||||
|
|
||||||
|
|||||||
1
debian/rules
vendored
1
debian/rules
vendored
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
override_dh_auto_clean:
|
override_dh_auto_clean:
|
||||||
rm -f dist/macos/Info.plist
|
rm -f dist/macos/Info.plist
|
||||||
rm -f dist/unix/PKGBUILD
|
|
||||||
rm -f dist/unix/strawberry.spec
|
rm -f dist/unix/strawberry.spec
|
||||||
rm -f dist/scripts/maketarball.sh
|
rm -f dist/scripts/maketarball.sh
|
||||||
rm -f dist/windows/strawberry.nsi
|
rm -f dist/windows/strawberry.nsi
|
||||||
|
|||||||
4
dist/CMakeLists.txt
vendored
4
dist/CMakeLists.txt
vendored
@@ -2,10 +2,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/maketarball.sh.in ${CMAKE_CUR
|
|||||||
if(RPM_DISTRO AND RPM_DATE)
|
if(RPM_DISTRO AND RPM_DATE)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/unix/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/unix/strawberry.spec @ONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/unix/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/unix/strawberry.spec @ONLY)
|
||||||
endif(RPM_DISTRO AND RPM_DATE)
|
endif(RPM_DISTRO AND RPM_DATE)
|
||||||
if(DEB_CODENAME AND DEB_DATE)
|
|
||||||
configure_file(${CMAKE_SOURCE_DIR}/debian/changelog.in ${CMAKE_SOURCE_DIR}/debian/changelog)
|
|
||||||
endif(DEB_CODENAME AND DEB_DATE)
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/unix/PKGBUILD.in ${CMAKE_CURRENT_SOURCE_DIR}/unix/PKGBUILD @ONLY)
|
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist.in ${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist.in ${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist)
|
||||||
|
|||||||
3
dist/scripts/maketarball.sh.in
vendored
3
dist/scripts/maketarball.sh.in
vendored
@@ -49,6 +49,7 @@ ${TAR} -cJf $name-$version.tar.xz \
|
|||||||
--exclude="*.nsi" \
|
--exclude="*.nsi" \
|
||||||
--exclude="*.kdev4" \
|
--exclude="*.kdev4" \
|
||||||
--exclude=".vscode" \
|
--exclude=".vscode" \
|
||||||
|
--exclude=".idea" \
|
||||||
--exclude="$root/.github" \
|
--exclude="$root/.github" \
|
||||||
--exclude="$root/.travis.yml" \
|
--exclude="$root/.travis.yml" \
|
||||||
--exclude="$root/.circleci" \
|
--exclude="$root/.circleci" \
|
||||||
@@ -56,11 +57,11 @@ ${TAR} -cJf $name-$version.tar.xz \
|
|||||||
--exclude="$root/CMakeLists.txt.user" \
|
--exclude="$root/CMakeLists.txt.user" \
|
||||||
--exclude="$root/.clang-format" \
|
--exclude="$root/.clang-format" \
|
||||||
--exclude="$root/build" \
|
--exclude="$root/build" \
|
||||||
|
--exclude="$root/cmake-build-debug" \
|
||||||
--exclude="$root/zanata.xml" \
|
--exclude="$root/zanata.xml" \
|
||||||
--exclude="$root/.zanata-cache" \
|
--exclude="$root/.zanata-cache" \
|
||||||
--exclude="$root/debian/changelog" \
|
--exclude="$root/debian/changelog" \
|
||||||
--exclude="$root/dist/scripts/maketarball.sh" \
|
--exclude="$root/dist/scripts/maketarball.sh" \
|
||||||
--exclude="$root/dist/unix/PKGBUILD" \
|
|
||||||
--exclude="$root/dist/macos/Info.plist" \
|
--exclude="$root/dist/macos/Info.plist" \
|
||||||
--exclude="$root/dist/windows/windres.rc" \
|
--exclude="$root/dist/windows/windres.rc" \
|
||||||
--exclude="$root/src/translations/translations.pot" \
|
--exclude="$root/src/translations/translations.pot" \
|
||||||
|
|||||||
56
dist/unix/PKGBUILD.in
vendored
56
dist/unix/PKGBUILD.in
vendored
@@ -1,56 +0,0 @@
|
|||||||
# Maintainer: Jonas Kvinge <jonas@jkvinge.net>
|
|
||||||
pkgname=strawberry
|
|
||||||
pkgver=@STRAWBERRY_VERSION_PAC_V@
|
|
||||||
pkgrel=@STRAWBERRY_VERSION_PAC_R@
|
|
||||||
pkgdesc="A music player aimed at audio enthusiasts and music collectors"
|
|
||||||
arch=(x86_64)
|
|
||||||
url="https://www.strawberrymusicplayer.org/"
|
|
||||||
license=(GPL3)
|
|
||||||
makedepends=(git cmake make gcc boost gettext qt5-tools)
|
|
||||||
depends=(
|
|
||||||
desktop-file-utils
|
|
||||||
hicolor-icon-theme
|
|
||||||
gnutls
|
|
||||||
udisks2
|
|
||||||
protobuf
|
|
||||||
qt5-base
|
|
||||||
qt5-x11extras
|
|
||||||
sqlite3
|
|
||||||
alsa-lib
|
|
||||||
libpulse
|
|
||||||
dbus
|
|
||||||
taglib
|
|
||||||
gstreamer
|
|
||||||
gst-plugins-base
|
|
||||||
gst-plugins-good
|
|
||||||
vlc
|
|
||||||
chromaprint
|
|
||||||
libgpod
|
|
||||||
libcdio
|
|
||||||
libmtp
|
|
||||||
fftw
|
|
||||||
)
|
|
||||||
optdepends=(
|
|
||||||
gst-plugins-bad
|
|
||||||
gst-plugins-ugly
|
|
||||||
gst-libav
|
|
||||||
)
|
|
||||||
provides=(strawberry)
|
|
||||||
conflicts=(strawberry)
|
|
||||||
source=("strawberry-@STRAWBERRY_VERSION_PACKAGE@.tar.xz")
|
|
||||||
sha256sums=('SKIP')
|
|
||||||
|
|
||||||
prepare() {
|
|
||||||
mkdir -p build
|
|
||||||
}
|
|
||||||
|
|
||||||
build() {
|
|
||||||
cd build
|
|
||||||
cmake ../${pkgname}-@STRAWBERRY_VERSION_PACKAGE@ -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j$(nproc)
|
|
||||||
}
|
|
||||||
|
|
||||||
package() {
|
|
||||||
cd build
|
|
||||||
make DESTDIR="${pkgdir}" install
|
|
||||||
}
|
|
||||||
@@ -9,18 +9,15 @@ TryExec=strawberry
|
|||||||
Icon=strawberry
|
Icon=strawberry
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Categories=AudioVideo;Player;Qt;Audio;
|
Categories=AudioVideo;Player;Qt;Audio;
|
||||||
|
Keywords=Audio;Player;
|
||||||
StartupNotify=false
|
StartupNotify=false
|
||||||
MimeType=x-content/audio-player;application/ogg;application/x-ogg;application/x-ogm-audio;audio/flac;audio/ogg;audio/vorbis;audio/aac;audio/mp4;audio/mpeg;audio/mpegurl;audio/vnd.rn-realaudio;audio/x-flac;audio/x-oggflac;audio/x-vorbis;audio/x-vorbis+ogg;audio/x-speex;audio/x-wav;audio/x-wavpack;audio/x-ape;audio/x-mp3;audio/x-mpeg;audio/x-mpegurl;audio/x-ms-wma;audio/x-musepack;audio/x-pn-realaudio;audio/x-scpls;video/x-ms-asf;x-scheme-handler/tidal;
|
MimeType=x-content/audio-player;application/ogg;application/x-ogg;application/x-ogm-audio;audio/flac;audio/ogg;audio/vorbis;audio/aac;audio/mp4;audio/mpeg;audio/mpegurl;audio/vnd.rn-realaudio;audio/x-flac;audio/x-oggflac;audio/x-vorbis;audio/x-vorbis+ogg;audio/x-speex;audio/x-wav;audio/x-wavpack;audio/x-ape;audio/x-mp3;audio/x-mpeg;audio/x-mpegurl;audio/x-ms-wma;audio/x-musepack;audio/x-pn-realaudio;audio/x-scpls;video/x-ms-asf;x-scheme-handler/tidal;
|
||||||
StartupWMClass=strawberry
|
StartupWMClass=strawberry
|
||||||
Actions=Play;Pause;Stop;StopAfterCurrent;Previous;Next;
|
Actions=Play-Pause;Stop;StopAfterCurrent;Previous;Next;
|
||||||
|
|
||||||
[Desktop Action Play]
|
[Desktop Action Play-Pause]
|
||||||
Name=Play
|
Name=Play/Pause
|
||||||
Exec=strawberry --play
|
Exec=strawberry --play-pause
|
||||||
|
|
||||||
[Desktop Action Pause]
|
|
||||||
Name=Pause
|
|
||||||
Exec=strawberry --pause
|
|
||||||
|
|
||||||
[Desktop Action Stop]
|
[Desktop Action Stop]
|
||||||
Name=Stop
|
Name=Stop
|
||||||
|
|||||||
2
dist/unix/strawberry.spec.in
vendored
2
dist/unix/strawberry.spec.in
vendored
@@ -49,6 +49,8 @@ BuildRequires: pkgconfig(sqlite3) >= 3.9
|
|||||||
BuildRequires: pkgconfig(taglib)
|
BuildRequires: pkgconfig(taglib)
|
||||||
%endif
|
%endif
|
||||||
BuildRequires: pkgconfig(fftw3)
|
BuildRequires: pkgconfig(fftw3)
|
||||||
|
BuildRequires: pkgconfig(icu-uc)
|
||||||
|
BuildRequires: pkgconfig(icu-i18n)
|
||||||
%if "@QT_VERSION_MAJOR@" == "5" && ( 0%{?fedora} || 0%{?rhel_version} || 0%{?centos} )
|
%if "@QT_VERSION_MAJOR@" == "5" && ( 0%{?fedora} || 0%{?rhel_version} || 0%{?centos} )
|
||||||
BuildRequires: pkgconfig(Qt@QT_VERSION_MAJOR@Core)
|
BuildRequires: pkgconfig(Qt@QT_VERSION_MAJOR@Core)
|
||||||
BuildRequires: pkgconfig(Qt@QT_VERSION_MAJOR@Gui)
|
BuildRequires: pkgconfig(Qt@QT_VERSION_MAJOR@Gui)
|
||||||
|
|||||||
170
dist/windows/strawberry.nsi.in
vendored
170
dist/windows/strawberry.nsi.in
vendored
@@ -42,6 +42,10 @@
|
|||||||
!define release
|
!define release
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
|
!if "@CMAKE_BUILD_TYPE@" == "RelWithDebInfo"
|
||||||
|
!define release
|
||||||
|
!endif
|
||||||
|
|
||||||
!if "@CMAKE_BUILD_TYPE@" == "Debug"
|
!if "@CMAKE_BUILD_TYPE@" == "Debug"
|
||||||
!define debug
|
!define debug
|
||||||
!undef build_type
|
!undef build_type
|
||||||
@@ -128,6 +132,9 @@ SetCompressor /SOLID lzma
|
|||||||
!insertmacro MUI_PAGE_LICENSE COPYING
|
!insertmacro MUI_PAGE_LICENSE COPYING
|
||||||
Page Custom LockedListPageShow
|
Page Custom LockedListPageShow
|
||||||
!insertmacro MUI_PAGE_DIRECTORY
|
!insertmacro MUI_PAGE_DIRECTORY
|
||||||
|
!ifdef msvc
|
||||||
|
Page Custom InstallMSVCRuntime
|
||||||
|
!endif
|
||||||
!insertmacro MUI_PAGE_INSTFILES
|
!insertmacro MUI_PAGE_INSTFILES
|
||||||
!insertmacro MUI_PAGE_FINISH
|
!insertmacro MUI_PAGE_FINISH
|
||||||
|
|
||||||
@@ -182,6 +189,20 @@ done:
|
|||||||
|
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
|
!ifdef msvc
|
||||||
|
!define vc_redist_file "vc_redist.${arch}.exe"
|
||||||
|
Function InstallMSVCRuntime
|
||||||
|
${registry::Read} "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\${arch}" "Version" $R0 $R1
|
||||||
|
${If} $R0 == ""
|
||||||
|
SetDetailsView hide
|
||||||
|
inetc::get /caption "Downloading..." "https://aka.ms/vs/17/release/${vc_redist_file}" "$TEMP\${vc_redist_file}" /end
|
||||||
|
ExecWait '"$TEMP\${vc_redist_file}" /install /passive'
|
||||||
|
Delete "$TEMP\${vc_redist_file}"
|
||||||
|
SetDetailsView show
|
||||||
|
${EndIf}
|
||||||
|
FunctionEnd
|
||||||
|
!endif
|
||||||
|
|
||||||
Function .onInit
|
Function .onInit
|
||||||
|
|
||||||
!insertmacro MUI_LANGDLL_DISPLAY
|
!insertmacro MUI_LANGDLL_DISPLAY
|
||||||
@@ -224,27 +245,28 @@ Section "Strawberry" Strawberry
|
|||||||
File "avfilter-8.dll"
|
File "avfilter-8.dll"
|
||||||
File "avformat-59.dll"
|
File "avformat-59.dll"
|
||||||
File "avutil-57.dll"
|
File "avutil-57.dll"
|
||||||
|
File "libFLAC-12.dll"
|
||||||
File "libbrotlicommon.dll"
|
File "libbrotlicommon.dll"
|
||||||
File "libbrotlidec.dll"
|
File "libbrotlidec.dll"
|
||||||
File "libbrotlienc.dll"
|
File "libbrotlienc.dll"
|
||||||
File "libbs2b-0.dll"
|
File "libbs2b-0.dll"
|
||||||
File "libbz2.dll"
|
File "libbz2.dll"
|
||||||
File "libcdio-19.dll"
|
|
||||||
File "libchromaprint.dll"
|
File "libchromaprint.dll"
|
||||||
File "libdl.dll"
|
File "libdl.dll"
|
||||||
File "libfdk-aac-2.dll"
|
|
||||||
File "libffi-8.dll"
|
|
||||||
File "libFLAC-8.dll"
|
|
||||||
File "libfreetype-6.dll"
|
|
||||||
File "libfaac-0.dll"
|
File "libfaac-0.dll"
|
||||||
File "libfaad-2.dll"
|
File "libfaad-2.dll"
|
||||||
File "libfftw3-3.dll"
|
File "libfdk-aac-2.dll"
|
||||||
|
File "libffi-8.dll"
|
||||||
|
File "libfreetype-6.dll"
|
||||||
|
File "libgcrypt-20.dll"
|
||||||
File "libgio-2.0-0.dll"
|
File "libgio-2.0-0.dll"
|
||||||
File "libglib-2.0-0.dll"
|
File "libglib-2.0-0.dll"
|
||||||
|
File "libgme.dll"
|
||||||
File "libgmodule-2.0-0.dll"
|
File "libgmodule-2.0-0.dll"
|
||||||
File "libgmp-10.dll"
|
File "libgmp-10.dll"
|
||||||
File "libgnutls-30.dll"
|
File "libgnutls-30.dll"
|
||||||
File "libgobject-2.0-0.dll"
|
File "libgobject-2.0-0.dll"
|
||||||
|
File "libgpg-error-0.dll"
|
||||||
File "libgstadaptivedemux-1.0-0.dll"
|
File "libgstadaptivedemux-1.0-0.dll"
|
||||||
File "libgstapp-1.0-0.dll"
|
File "libgstapp-1.0-0.dll"
|
||||||
File "libgstaudio-1.0-0.dll"
|
File "libgstaudio-1.0-0.dll"
|
||||||
@@ -278,20 +300,19 @@ Section "Strawberry" Strawberry
|
|||||||
File "libopenmpt-0.dll"
|
File "libopenmpt-0.dll"
|
||||||
File "libopus-0.dll"
|
File "libopus-0.dll"
|
||||||
File "liborc-0.4-0.dll"
|
File "liborc-0.4-0.dll"
|
||||||
File "libpcre-1.dll"
|
|
||||||
File "libpcre2-16-0.dll"
|
|
||||||
File "libpng16-16.dll"
|
File "libpng16-16.dll"
|
||||||
File "libprotobuf-31.dll"
|
File "libprotobuf-32.dll"
|
||||||
File "libpsl-5.dll"
|
File "libpsl-5.dll"
|
||||||
File "libqtsparkle-qt6.dll"
|
File "libqtsparkle-qt6.dll"
|
||||||
File "libsoup-2.4-1.dll"
|
File "libsoup-3.0-0.dll"
|
||||||
File "libspeex-1.dll"
|
File "libspeex-1.dll"
|
||||||
File "libsqlite3-0.dll"
|
File "libsqlite3-0.dll"
|
||||||
File "libssp-0.dll"
|
File "libssp-0.dll"
|
||||||
File "libstdc++-6.dll"
|
File "libstdc++-6.dll"
|
||||||
File "libtag.dll"
|
File "libtag.dll"
|
||||||
File "libtasn1-6.dll"
|
File "libtasn1-6.dll"
|
||||||
File "libunistring-2.dll"
|
File "libtwolame-0.dll"
|
||||||
|
File "libunistring-5.dll"
|
||||||
File "libvorbis-0.dll"
|
File "libvorbis-0.dll"
|
||||||
File "libvorbisenc-2.dll"
|
File "libvorbisenc-2.dll"
|
||||||
File "libvorbisfile-3.dll"
|
File "libvorbisfile-3.dll"
|
||||||
@@ -309,8 +330,13 @@ Section "Strawberry" Strawberry
|
|||||||
File "libexpat-1.dll"
|
File "libexpat-1.dll"
|
||||||
File "libmman.dll"
|
File "libmman.dll"
|
||||||
File "libmpfr-6.dll"
|
File "libmpfr-6.dll"
|
||||||
|
File "libpcre2-8d.dll"
|
||||||
|
File "libpcre2-16d.dll"
|
||||||
File "libreadline8.dll"
|
File "libreadline8.dll"
|
||||||
File "libtermcap.dll"
|
File "libtermcap.dll"
|
||||||
|
!else
|
||||||
|
File "libpcre2-8.dll"
|
||||||
|
File "libpcre2-16.dll"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
!endif ; MinGW
|
!endif ; MinGW
|
||||||
@@ -328,15 +354,20 @@ Section "Strawberry" Strawberry
|
|||||||
File "libssl-3-x64.dll"
|
File "libssl-3-x64.dll"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
|
File "FLAC.dll"
|
||||||
|
File "avcodec-58.dll"
|
||||||
|
File "avfilter-7.dll"
|
||||||
|
File "avformat-58.dll"
|
||||||
|
File "avutil-56.dll"
|
||||||
File "brotlicommon.dll"
|
File "brotlicommon.dll"
|
||||||
File "brotlidec.dll"
|
File "brotlidec.dll"
|
||||||
File "chromaprint.dll"
|
File "chromaprint.dll"
|
||||||
File "faad.dll"
|
File "faad.dll"
|
||||||
File "fdk-aac.dll"
|
File "fdk-aac.dll"
|
||||||
File "ffi-7.dll"
|
File "ffi-7.dll"
|
||||||
File "FLAC.dll"
|
|
||||||
File "gio-2.0-0.dll"
|
File "gio-2.0-0.dll"
|
||||||
File "glib-2.0-0.dll"
|
File "glib-2.0-0.dll"
|
||||||
|
File "gme.dll"
|
||||||
File "gmodule-2.0-0.dll"
|
File "gmodule-2.0-0.dll"
|
||||||
File "gnutls.dll"
|
File "gnutls.dll"
|
||||||
File "gobject-2.0-0.dll"
|
File "gobject-2.0-0.dll"
|
||||||
@@ -357,9 +388,9 @@ Section "Strawberry" Strawberry
|
|||||||
File "gsttag-1.0-0.dll"
|
File "gsttag-1.0-0.dll"
|
||||||
File "gsturidownloader-1.0-0.dll"
|
File "gsturidownloader-1.0-0.dll"
|
||||||
File "gstvideo-1.0-0.dll"
|
File "gstvideo-1.0-0.dll"
|
||||||
File "gstwinrt-1.0-0.dll"
|
File "harfbuzz.dll"
|
||||||
File "fftw3.dll"
|
|
||||||
File "intl-8.dll"
|
File "intl-8.dll"
|
||||||
|
File "jpeg62.dll"
|
||||||
File "libbs2b.dll"
|
File "libbs2b.dll"
|
||||||
File "libfaac_dll.dll"
|
File "libfaac_dll.dll"
|
||||||
File "libiconv.dll"
|
File "libiconv.dll"
|
||||||
@@ -369,30 +400,40 @@ Section "Strawberry" Strawberry
|
|||||||
File "libspeex.dll"
|
File "libspeex.dll"
|
||||||
File "mpcdec.dll"
|
File "mpcdec.dll"
|
||||||
File "mpg123.dll"
|
File "mpg123.dll"
|
||||||
|
File "nghttp2.dll"
|
||||||
File "ogg.dll"
|
File "ogg.dll"
|
||||||
File "opus.dll"
|
File "opus.dll"
|
||||||
File "orc-0.4-0.dll"
|
File "orc-0.4-0.dll"
|
||||||
|
File "postproc-55.dll"
|
||||||
File "psl-5.dll"
|
File "psl-5.dll"
|
||||||
File "qtsparkle-qt6.dll"
|
File "qtsparkle-qt6.dll"
|
||||||
File "soup-2.4-1.dll"
|
File "soup-3.0-0.dll"
|
||||||
File "sqlite3.dll"
|
File "sqlite3.dll"
|
||||||
|
File "swresample-3.dll"
|
||||||
|
File "swscale-5.dll"
|
||||||
File "tag.dll"
|
File "tag.dll"
|
||||||
File "vorbis.dll"
|
File "vorbis.dll"
|
||||||
File "vorbisfile.dll"
|
File "vorbisfile.dll"
|
||||||
File "wavpackdll.dll"
|
File "wavpackdll.dll"
|
||||||
|
|
||||||
!ifdef release
|
!ifdef release
|
||||||
|
File "freetype.dll"
|
||||||
File "libpng16.dll"
|
File "libpng16.dll"
|
||||||
File "libprotobuf.dll"
|
File "libprotobuf.dll"
|
||||||
File "libxml2.dll"
|
File "libxml2.dll"
|
||||||
|
File "pcre2-8.dll"
|
||||||
File "pcre2-16.dll"
|
File "pcre2-16.dll"
|
||||||
|
File "twolame.dll"
|
||||||
File "zlib.dll"
|
File "zlib.dll"
|
||||||
!endif
|
!endif
|
||||||
!ifdef debug
|
!ifdef debug
|
||||||
|
File "freetyped.dll"
|
||||||
File "libpng16d.dll"
|
File "libpng16d.dll"
|
||||||
File "libprotobufd.dll"
|
File "libprotobufd.dll"
|
||||||
File "libxml2d.dll"
|
File "libxml2d.dll"
|
||||||
|
File "pcre2-8d.dll"
|
||||||
File "pcre2-16d.dll"
|
File "pcre2-16d.dll"
|
||||||
|
File "twolamed.dll"
|
||||||
File "zlibd.dll"
|
File "zlibd.dll"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
@@ -400,7 +441,11 @@ Section "Strawberry" Strawberry
|
|||||||
|
|
||||||
; Common files
|
; Common files
|
||||||
|
|
||||||
|
File "icudt72.dll"
|
||||||
|
File "libfftw3-3.dll"
|
||||||
!ifdef msvc && debug
|
!ifdef msvc && debug
|
||||||
|
File "icuin72d.dll"
|
||||||
|
File "icuuc72d.dll"
|
||||||
File "Qt6Concurrentd.dll"
|
File "Qt6Concurrentd.dll"
|
||||||
File "Qt6Cored.dll"
|
File "Qt6Cored.dll"
|
||||||
File "Qt6Guid.dll"
|
File "Qt6Guid.dll"
|
||||||
@@ -408,6 +453,8 @@ Section "Strawberry" Strawberry
|
|||||||
File "Qt6Sqld.dll"
|
File "Qt6Sqld.dll"
|
||||||
File "Qt6Widgetsd.dll"
|
File "Qt6Widgetsd.dll"
|
||||||
!else
|
!else
|
||||||
|
File "icuin72.dll"
|
||||||
|
File "icuuc72.dll"
|
||||||
File "Qt6Concurrent.dll"
|
File "Qt6Concurrent.dll"
|
||||||
File "Qt6Core.dll"
|
File "Qt6Core.dll"
|
||||||
File "Qt6Gui.dll"
|
File "Qt6Gui.dll"
|
||||||
@@ -481,8 +528,10 @@ SectionEnd
|
|||||||
Section "Qt TLS plugins" tls
|
Section "Qt TLS plugins" tls
|
||||||
SetOutPath "$INSTDIR\tls"
|
SetOutPath "$INSTDIR\tls"
|
||||||
!ifdef msvc && debug
|
!ifdef msvc && debug
|
||||||
|
File "/oname=qschannelbackendd.dll" "tls\qschannelbackendd.dll"
|
||||||
File "/oname=qopensslbackendd.dll" "tls\qopensslbackendd.dll"
|
File "/oname=qopensslbackendd.dll" "tls\qopensslbackendd.dll"
|
||||||
!else
|
!else
|
||||||
|
File "/oname=qschannelbackend.dll" "tls\qschannelbackend.dll"
|
||||||
File "/oname=qopensslbackend.dll" "tls\qopensslbackend.dll"
|
File "/oname=qopensslbackend.dll" "tls\qopensslbackend.dll"
|
||||||
!endif
|
!endif
|
||||||
SectionEnd
|
SectionEnd
|
||||||
@@ -528,7 +577,6 @@ Section "Gstreamer plugins" gstreamer-plugins
|
|||||||
File "/oname=libgstaudiotestsrc.dll" "gstreamer-plugins\libgstaudiotestsrc.dll"
|
File "/oname=libgstaudiotestsrc.dll" "gstreamer-plugins\libgstaudiotestsrc.dll"
|
||||||
File "/oname=libgstautodetect.dll" "gstreamer-plugins\libgstautodetect.dll"
|
File "/oname=libgstautodetect.dll" "gstreamer-plugins\libgstautodetect.dll"
|
||||||
File "/oname=libgstbs2b.dll" "gstreamer-plugins\libgstbs2b.dll"
|
File "/oname=libgstbs2b.dll" "gstreamer-plugins\libgstbs2b.dll"
|
||||||
File "/oname=libgstcdio.dll" "gstreamer-plugins\libgstcdio.dll"
|
|
||||||
File "/oname=libgstcoreelements.dll" "gstreamer-plugins\libgstcoreelements.dll"
|
File "/oname=libgstcoreelements.dll" "gstreamer-plugins\libgstcoreelements.dll"
|
||||||
File "/oname=libgstdash.dll" "gstreamer-plugins\libgstdash.dll"
|
File "/oname=libgstdash.dll" "gstreamer-plugins\libgstdash.dll"
|
||||||
File "/oname=libgstdirectsound.dll" "gstreamer-plugins\libgstdirectsound.dll"
|
File "/oname=libgstdirectsound.dll" "gstreamer-plugins\libgstdirectsound.dll"
|
||||||
@@ -538,9 +586,11 @@ Section "Gstreamer plugins" gstreamer-plugins
|
|||||||
File "/oname=libgstfdkaac.dll" "gstreamer-plugins\libgstfdkaac.dll"
|
File "/oname=libgstfdkaac.dll" "gstreamer-plugins\libgstfdkaac.dll"
|
||||||
File "/oname=libgstflac.dll" "gstreamer-plugins\libgstflac.dll"
|
File "/oname=libgstflac.dll" "gstreamer-plugins\libgstflac.dll"
|
||||||
File "/oname=libgstgio.dll" "gstreamer-plugins\libgstgio.dll"
|
File "/oname=libgstgio.dll" "gstreamer-plugins\libgstgio.dll"
|
||||||
|
File "/oname=libgstgme.dll" "gstreamer-plugins\libgstgme.dll"
|
||||||
File "/oname=libgsthls.dll" "gstreamer-plugins\libgsthls.dll"
|
File "/oname=libgsthls.dll" "gstreamer-plugins\libgsthls.dll"
|
||||||
File "/oname=libgsticydemux.dll" "gstreamer-plugins\libgsticydemux.dll"
|
File "/oname=libgsticydemux.dll" "gstreamer-plugins\libgsticydemux.dll"
|
||||||
File "/oname=libgstid3demux.dll" "gstreamer-plugins\libgstid3demux.dll"
|
File "/oname=libgstid3demux.dll" "gstreamer-plugins\libgstid3demux.dll"
|
||||||
|
File "/oname=libgstid3tag.dll" "gstreamer-plugins\libgstid3tag.dll"
|
||||||
File "/oname=libgstisomp4.dll" "gstreamer-plugins\libgstisomp4.dll"
|
File "/oname=libgstisomp4.dll" "gstreamer-plugins\libgstisomp4.dll"
|
||||||
File "/oname=libgstlame.dll" "gstreamer-plugins\libgstlame.dll"
|
File "/oname=libgstlame.dll" "gstreamer-plugins\libgstlame.dll"
|
||||||
File "/oname=libgstlibav.dll" "gstreamer-plugins\libgstlibav.dll"
|
File "/oname=libgstlibav.dll" "gstreamer-plugins\libgstlibav.dll"
|
||||||
@@ -560,17 +610,20 @@ Section "Gstreamer plugins" gstreamer-plugins
|
|||||||
File "/oname=libgstspeex.dll" "gstreamer-plugins\libgstspeex.dll"
|
File "/oname=libgstspeex.dll" "gstreamer-plugins\libgstspeex.dll"
|
||||||
File "/oname=libgsttaglib.dll" "gstreamer-plugins\libgsttaglib.dll"
|
File "/oname=libgsttaglib.dll" "gstreamer-plugins\libgsttaglib.dll"
|
||||||
File "/oname=libgsttcp.dll" "gstreamer-plugins\libgsttcp.dll"
|
File "/oname=libgsttcp.dll" "gstreamer-plugins\libgsttcp.dll"
|
||||||
|
File "/oname=libgsttwolame.dll" "gstreamer-plugins\libgsttwolame.dll"
|
||||||
File "/oname=libgsttypefindfunctions.dll" "gstreamer-plugins\libgsttypefindfunctions.dll"
|
File "/oname=libgsttypefindfunctions.dll" "gstreamer-plugins\libgsttypefindfunctions.dll"
|
||||||
File "/oname=libgstudp.dll" "gstreamer-plugins\libgstudp.dll"
|
File "/oname=libgstudp.dll" "gstreamer-plugins\libgstudp.dll"
|
||||||
File "/oname=libgstvolume.dll" "gstreamer-plugins\libgstvolume.dll"
|
File "/oname=libgstvolume.dll" "gstreamer-plugins\libgstvolume.dll"
|
||||||
File "/oname=libgstvorbis.dll" "gstreamer-plugins\libgstvorbis.dll"
|
File "/oname=libgstvorbis.dll" "gstreamer-plugins\libgstvorbis.dll"
|
||||||
File "/oname=libgstwasapi.dll" "gstreamer-plugins\libgstwasapi.dll"
|
File "/oname=libgstwasapi.dll" "gstreamer-plugins\libgstwasapi.dll"
|
||||||
|
File "/oname=libgstwavenc.dll" "gstreamer-plugins\libgstwavenc.dll"
|
||||||
File "/oname=libgstwavpack.dll" "gstreamer-plugins\libgstwavpack.dll"
|
File "/oname=libgstwavpack.dll" "gstreamer-plugins\libgstwavpack.dll"
|
||||||
File "/oname=libgstwavparse.dll" "gstreamer-plugins\libgstwavparse.dll"
|
File "/oname=libgstwavparse.dll" "gstreamer-plugins\libgstwavparse.dll"
|
||||||
File "/oname=libgstxingmux.dll" "gstreamer-plugins\libgstxingmux.dll"
|
File "/oname=libgstxingmux.dll" "gstreamer-plugins\libgstxingmux.dll"
|
||||||
!endif ; MinGW
|
!endif ; MinGW
|
||||||
|
|
||||||
!ifdef msvc
|
!ifdef msvc
|
||||||
|
File "/oname=gstaes.dll" "gstreamer-plugins\gstaes.dll"
|
||||||
File "/oname=gstaiff.dll" "gstreamer-plugins\gstaiff.dll"
|
File "/oname=gstaiff.dll" "gstreamer-plugins\gstaiff.dll"
|
||||||
File "/oname=gstapetag.dll" "gstreamer-plugins\gstapetag.dll"
|
File "/oname=gstapetag.dll" "gstreamer-plugins\gstapetag.dll"
|
||||||
File "/oname=gstapp.dll" "gstreamer-plugins\gstapp.dll"
|
File "/oname=gstapp.dll" "gstreamer-plugins\gstapp.dll"
|
||||||
@@ -594,31 +647,37 @@ Section "Gstreamer plugins" gstreamer-plugins
|
|||||||
File "/oname=gstfdkaac.dll" "gstreamer-plugins\gstfdkaac.dll"
|
File "/oname=gstfdkaac.dll" "gstreamer-plugins\gstfdkaac.dll"
|
||||||
File "/oname=gstflac.dll" "gstreamer-plugins\gstflac.dll"
|
File "/oname=gstflac.dll" "gstreamer-plugins\gstflac.dll"
|
||||||
File "/oname=gstgio.dll" "gstreamer-plugins\gstgio.dll"
|
File "/oname=gstgio.dll" "gstreamer-plugins\gstgio.dll"
|
||||||
|
File "/oname=gstgme.dll" "gstreamer-plugins\gstgme.dll"
|
||||||
File "/oname=gsthls.dll" "gstreamer-plugins\gsthls.dll"
|
File "/oname=gsthls.dll" "gstreamer-plugins\gsthls.dll"
|
||||||
File "/oname=gsticydemux.dll" "gstreamer-plugins\gsticydemux.dll"
|
File "/oname=gsticydemux.dll" "gstreamer-plugins\gsticydemux.dll"
|
||||||
File "/oname=gstid3demux.dll" "gstreamer-plugins\gstid3demux.dll"
|
File "/oname=gstid3demux.dll" "gstreamer-plugins\gstid3demux.dll"
|
||||||
|
File "/oname=gstid3tag.dll" "gstreamer-plugins\gstid3tag.dll"
|
||||||
File "/oname=gstisomp4.dll" "gstreamer-plugins\gstisomp4.dll"
|
File "/oname=gstisomp4.dll" "gstreamer-plugins\gstisomp4.dll"
|
||||||
File "/oname=gstlame.dll" "gstreamer-plugins\gstlame.dll"
|
File "/oname=gstlame.dll" "gstreamer-plugins\gstlame.dll"
|
||||||
|
File "/oname=gstlibav.dll" "gstreamer-plugins\gstlibav.dll"
|
||||||
File "/oname=gstmpg123.dll" "gstreamer-plugins\gstmpg123.dll"
|
File "/oname=gstmpg123.dll" "gstreamer-plugins\gstmpg123.dll"
|
||||||
File "/oname=gstmusepack.dll" "gstreamer-plugins\gstmusepack.dll"
|
File "/oname=gstmusepack.dll" "gstreamer-plugins\gstmusepack.dll"
|
||||||
File "/oname=gstogg.dll" "gstreamer-plugins\gstogg.dll"
|
File "/oname=gstogg.dll" "gstreamer-plugins\gstogg.dll"
|
||||||
File "/oname=gstopenmpt.dll" "gstreamer-plugins\gstopenmpt.dll"
|
File "/oname=gstopenmpt.dll" "gstreamer-plugins\gstopenmpt.dll"
|
||||||
File "/oname=gstopus.dll" "gstreamer-plugins\gstopus.dll"
|
File "/oname=gstopus.dll" "gstreamer-plugins\gstopus.dll"
|
||||||
File "/oname=gstopusparse.dll" "gstreamer-plugins\gstopusparse.dll"
|
File "/oname=gstopusparse.dll" "gstreamer-plugins\gstopusparse.dll"
|
||||||
|
File "/oname=gstpbtypes.dll" "gstreamer-plugins\gstpbtypes.dll"
|
||||||
File "/oname=gstplayback.dll" "gstreamer-plugins\gstplayback.dll"
|
File "/oname=gstplayback.dll" "gstreamer-plugins\gstplayback.dll"
|
||||||
File "/oname=gstreplaygain.dll" "gstreamer-plugins\gstreplaygain.dll"
|
File "/oname=gstreplaygain.dll" "gstreamer-plugins\gstreplaygain.dll"
|
||||||
File "/oname=gstrtp.dll" "gstreamer-plugins\gstrtp.dll"
|
File "/oname=gstrtp.dll" "gstreamer-plugins\gstrtp.dll"
|
||||||
File "/oname=gstrtsp.dll" "gstreamer-plugins\gstrtsp.dll"
|
File "/oname=gstrtsp.dll" "gstreamer-plugins\gstrtsp.dll"
|
||||||
File "/oname=gstspeex.dll" "gstreamer-plugins\gstspeex.dll"
|
|
||||||
File "/oname=gstsoup.dll" "gstreamer-plugins\gstsoup.dll"
|
File "/oname=gstsoup.dll" "gstreamer-plugins\gstsoup.dll"
|
||||||
File "/oname=gstspectrum.dll" "gstreamer-plugins\gstspectrum.dll"
|
File "/oname=gstspectrum.dll" "gstreamer-plugins\gstspectrum.dll"
|
||||||
|
File "/oname=gstspeex.dll" "gstreamer-plugins\gstspeex.dll"
|
||||||
|
File "/oname=gsttaglib.dll" "gstreamer-plugins\gsttaglib.dll"
|
||||||
File "/oname=gsttcp.dll" "gstreamer-plugins\gsttcp.dll"
|
File "/oname=gsttcp.dll" "gstreamer-plugins\gsttcp.dll"
|
||||||
|
File "/oname=gsttwolame.dll" "gstreamer-plugins\gsttwolame.dll"
|
||||||
File "/oname=gsttypefindfunctions.dll" "gstreamer-plugins\gsttypefindfunctions.dll"
|
File "/oname=gsttypefindfunctions.dll" "gstreamer-plugins\gsttypefindfunctions.dll"
|
||||||
File "/oname=gstudp.dll" "gstreamer-plugins\gstudp.dll"
|
File "/oname=gstudp.dll" "gstreamer-plugins\gstudp.dll"
|
||||||
File "/oname=gstvolume.dll" "gstreamer-plugins\gstvolume.dll"
|
File "/oname=gstvolume.dll" "gstreamer-plugins\gstvolume.dll"
|
||||||
File "/oname=gstvorbis.dll" "gstreamer-plugins\gstvorbis.dll"
|
File "/oname=gstvorbis.dll" "gstreamer-plugins\gstvorbis.dll"
|
||||||
File "/oname=gstwasapi.dll" "gstreamer-plugins\gstwasapi.dll"
|
File "/oname=gstwasapi.dll" "gstreamer-plugins\gstwasapi.dll"
|
||||||
;File "/oname=gstwasapi2.dll" "gstreamer-plugins\gstwasapi2.dll"
|
File "/oname=gstwavenc.dll" "gstreamer-plugins\gstwavenc.dll"
|
||||||
File "/oname=gstwavpack.dll" "gstreamer-plugins\gstwavpack.dll"
|
File "/oname=gstwavpack.dll" "gstreamer-plugins\gstwavpack.dll"
|
||||||
File "/oname=gstwavparse.dll" "gstreamer-plugins\gstwavparse.dll"
|
File "/oname=gstwavparse.dll" "gstreamer-plugins\gstwavparse.dll"
|
||||||
File "/oname=gstxingmux.dll" "gstreamer-plugins\gstxingmux.dll"
|
File "/oname=gstxingmux.dll" "gstreamer-plugins\gstxingmux.dll"
|
||||||
@@ -688,27 +747,28 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\avfilter-8.dll"
|
Delete "$INSTDIR\avfilter-8.dll"
|
||||||
Delete "$INSTDIR\avformat-59.dll"
|
Delete "$INSTDIR\avformat-59.dll"
|
||||||
Delete "$INSTDIR\avutil-57.dll"
|
Delete "$INSTDIR\avutil-57.dll"
|
||||||
|
Delete "$INSTDIR\libFLAC-12.dll"
|
||||||
Delete "$INSTDIR\libbrotlicommon.dll"
|
Delete "$INSTDIR\libbrotlicommon.dll"
|
||||||
Delete "$INSTDIR\libbrotlidec.dll"
|
Delete "$INSTDIR\libbrotlidec.dll"
|
||||||
Delete "$INSTDIR\libbrotlienc.dll"
|
Delete "$INSTDIR\libbrotlienc.dll"
|
||||||
Delete "$INSTDIR\libbs2b-0.dll"
|
Delete "$INSTDIR\libbs2b-0.dll"
|
||||||
Delete "$INSTDIR\libbz2.dll"
|
Delete "$INSTDIR\libbz2.dll"
|
||||||
Delete "$INSTDIR\libcdio-19.dll"
|
|
||||||
Delete "$INSTDIR\libchromaprint.dll"
|
Delete "$INSTDIR\libchromaprint.dll"
|
||||||
Delete "$INSTDIR\libdl.dll"
|
Delete "$INSTDIR\libdl.dll"
|
||||||
Delete "$INSTDIR\libfdk-aac-2.dll"
|
|
||||||
Delete "$INSTDIR\libffi-8.dll"
|
|
||||||
Delete "$INSTDIR\libFLAC-8.dll"
|
|
||||||
Delete "$INSTDIR\libfreetype-6.dll"
|
|
||||||
Delete "$INSTDIR\libfaac-0.dll"
|
Delete "$INSTDIR\libfaac-0.dll"
|
||||||
Delete "$INSTDIR\libfaad-2.dll"
|
Delete "$INSTDIR\libfaad-2.dll"
|
||||||
Delete "$INSTDIR\libfftw3-3.dll"
|
Delete "$INSTDIR\libfdk-aac-2.dll"
|
||||||
|
Delete "$INSTDIR\libffi-8.dll"
|
||||||
|
Delete "$INSTDIR\libfreetype-6.dll"
|
||||||
|
Delete "$INSTDIR\libgcrypt-20.dll"
|
||||||
Delete "$INSTDIR\libgio-2.0-0.dll"
|
Delete "$INSTDIR\libgio-2.0-0.dll"
|
||||||
Delete "$INSTDIR\libglib-2.0-0.dll"
|
Delete "$INSTDIR\libglib-2.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgme.dll"
|
||||||
Delete "$INSTDIR\libgmodule-2.0-0.dll"
|
Delete "$INSTDIR\libgmodule-2.0-0.dll"
|
||||||
Delete "$INSTDIR\libgmp-10.dll"
|
Delete "$INSTDIR\libgmp-10.dll"
|
||||||
Delete "$INSTDIR\libgnutls-30.dll"
|
Delete "$INSTDIR\libgnutls-30.dll"
|
||||||
Delete "$INSTDIR\libgobject-2.0-0.dll"
|
Delete "$INSTDIR\libgobject-2.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgpg-error-0.dll"
|
||||||
Delete "$INSTDIR\libgstadaptivedemux-1.0-0.dll"
|
Delete "$INSTDIR\libgstadaptivedemux-1.0-0.dll"
|
||||||
Delete "$INSTDIR\libgstapp-1.0-0.dll"
|
Delete "$INSTDIR\libgstapp-1.0-0.dll"
|
||||||
Delete "$INSTDIR\libgstaudio-1.0-0.dll"
|
Delete "$INSTDIR\libgstaudio-1.0-0.dll"
|
||||||
@@ -742,20 +802,19 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libopenmpt-0.dll"
|
Delete "$INSTDIR\libopenmpt-0.dll"
|
||||||
Delete "$INSTDIR\libopus-0.dll"
|
Delete "$INSTDIR\libopus-0.dll"
|
||||||
Delete "$INSTDIR\liborc-0.4-0.dll"
|
Delete "$INSTDIR\liborc-0.4-0.dll"
|
||||||
Delete "$INSTDIR\libpcre-1.dll"
|
|
||||||
Delete "$INSTDIR\libpcre2-16-0.dll"
|
|
||||||
Delete "$INSTDIR\libpng16-16.dll"
|
Delete "$INSTDIR\libpng16-16.dll"
|
||||||
Delete "$INSTDIR\libprotobuf-31.dll"
|
Delete "$INSTDIR\libprotobuf-32.dll"
|
||||||
Delete "$INSTDIR\libpsl-5.dll"
|
Delete "$INSTDIR\libpsl-5.dll"
|
||||||
Delete "$INSTDIR\libqtsparkle-qt6.dll"
|
Delete "$INSTDIR\libqtsparkle-qt6.dll"
|
||||||
Delete "$INSTDIR\libsoup-2.4-1.dll"
|
Delete "$INSTDIR\libsoup-3.0-0.dll"
|
||||||
Delete "$INSTDIR\libspeex-1.dll"
|
Delete "$INSTDIR\libspeex-1.dll"
|
||||||
Delete "$INSTDIR\libsqlite3-0.dll"
|
Delete "$INSTDIR\libsqlite3-0.dll"
|
||||||
Delete "$INSTDIR\libssp-0.dll"
|
Delete "$INSTDIR\libssp-0.dll"
|
||||||
Delete "$INSTDIR\libstdc++-6.dll"
|
Delete "$INSTDIR\libstdc++-6.dll"
|
||||||
Delete "$INSTDIR\libtag.dll"
|
Delete "$INSTDIR\libtag.dll"
|
||||||
Delete "$INSTDIR\libtasn1-6.dll"
|
Delete "$INSTDIR\libtasn1-6.dll"
|
||||||
Delete "$INSTDIR\libunistring-2.dll"
|
Delete "$INSTDIR\libtwolame-0.dll"
|
||||||
|
Delete "$INSTDIR\libunistring-5.dll"
|
||||||
Delete "$INSTDIR\libvorbis-0.dll"
|
Delete "$INSTDIR\libvorbis-0.dll"
|
||||||
Delete "$INSTDIR\libvorbisenc-2.dll"
|
Delete "$INSTDIR\libvorbisenc-2.dll"
|
||||||
Delete "$INSTDIR\libvorbisfile-3.dll"
|
Delete "$INSTDIR\libvorbisfile-3.dll"
|
||||||
@@ -768,14 +827,18 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\swscale-6.dll"
|
Delete "$INSTDIR\swscale-6.dll"
|
||||||
Delete "$INSTDIR\zlib1.dll"
|
Delete "$INSTDIR\zlib1.dll"
|
||||||
|
|
||||||
|
|
||||||
!ifdef debug
|
!ifdef debug
|
||||||
Delete "$INSTDIR\gdb.exe"
|
Delete "$INSTDIR\gdb.exe"
|
||||||
Delete "$INSTDIR\libexpat-1.dll"
|
Delete "$INSTDIR\libexpat-1.dll"
|
||||||
Delete "$INSTDIR\libmman.dll"
|
Delete "$INSTDIR\libmman.dll"
|
||||||
Delete "$INSTDIR\libmpfr-6.dll"
|
Delete "$INSTDIR\libmpfr-6.dll"
|
||||||
|
Delete "$INSTDIR\libpcre2-8d.dll"
|
||||||
|
Delete "$INSTDIR\libpcre2-16d.dll"
|
||||||
Delete "$INSTDIR\libreadline8.dll"
|
Delete "$INSTDIR\libreadline8.dll"
|
||||||
Delete "$INSTDIR\libtermcap.dll"
|
Delete "$INSTDIR\libtermcap.dll"
|
||||||
|
!else
|
||||||
|
Delete "$INSTDIR\libpcre2-8.dll"
|
||||||
|
Delete "$INSTDIR\libpcre2-16.dll"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
!endif ; MinGW
|
!endif ; MinGW
|
||||||
@@ -793,15 +856,20 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libssl-3-x64.dll"
|
Delete "$INSTDIR\libssl-3-x64.dll"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
|
Delete "$INSTDIR\FLAC.dll"
|
||||||
|
Delete "$INSTDIR\avcodec-58.dll"
|
||||||
|
Delete "$INSTDIR\avfilter-7.dll"
|
||||||
|
Delete "$INSTDIR\avformat-58.dll"
|
||||||
|
Delete "$INSTDIR\avutil-56.dll"
|
||||||
Delete "$INSTDIR\brotlicommon.dll"
|
Delete "$INSTDIR\brotlicommon.dll"
|
||||||
Delete "$INSTDIR\brotlidec.dll"
|
Delete "$INSTDIR\brotlidec.dll"
|
||||||
Delete "$INSTDIR\chromaprint.dll"
|
Delete "$INSTDIR\chromaprint.dll"
|
||||||
Delete "$INSTDIR\faad.dll"
|
Delete "$INSTDIR\faad.dll"
|
||||||
Delete "$INSTDIR\fdk-aac.dll"
|
Delete "$INSTDIR\fdk-aac.dll"
|
||||||
Delete "$INSTDIR\ffi-7.dll"
|
Delete "$INSTDIR\ffi-7.dll"
|
||||||
Delete "$INSTDIR\FLAC.dll"
|
|
||||||
Delete "$INSTDIR\gio-2.0-0.dll"
|
Delete "$INSTDIR\gio-2.0-0.dll"
|
||||||
Delete "$INSTDIR\glib-2.0-0.dll"
|
Delete "$INSTDIR\glib-2.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gme.dll"
|
||||||
Delete "$INSTDIR\gmodule-2.0-0.dll"
|
Delete "$INSTDIR\gmodule-2.0-0.dll"
|
||||||
Delete "$INSTDIR\gnutls.dll"
|
Delete "$INSTDIR\gnutls.dll"
|
||||||
Delete "$INSTDIR\gobject-2.0-0.dll"
|
Delete "$INSTDIR\gobject-2.0-0.dll"
|
||||||
@@ -822,9 +890,9 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\gsttag-1.0-0.dll"
|
Delete "$INSTDIR\gsttag-1.0-0.dll"
|
||||||
Delete "$INSTDIR\gsturidownloader-1.0-0.dll"
|
Delete "$INSTDIR\gsturidownloader-1.0-0.dll"
|
||||||
Delete "$INSTDIR\gstvideo-1.0-0.dll"
|
Delete "$INSTDIR\gstvideo-1.0-0.dll"
|
||||||
Delete "$INSTDIR\gstwinrt-1.0-0.dll"
|
Delete "$INSTDIR\harfbuzz.dll"
|
||||||
Delete "$INSTDIR\fftw3.dll"
|
|
||||||
Delete "$INSTDIR\intl-8.dll"
|
Delete "$INSTDIR\intl-8.dll"
|
||||||
|
Delete "$INSTDIR\jpeg62.dll"
|
||||||
Delete "$INSTDIR\libbs2b.dll"
|
Delete "$INSTDIR\libbs2b.dll"
|
||||||
Delete "$INSTDIR\libfaac_dll.dll"
|
Delete "$INSTDIR\libfaac_dll.dll"
|
||||||
Delete "$INSTDIR\libiconv.dll"
|
Delete "$INSTDIR\libiconv.dll"
|
||||||
@@ -834,30 +902,40 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libspeex.dll"
|
Delete "$INSTDIR\libspeex.dll"
|
||||||
Delete "$INSTDIR\mpcdec.dll"
|
Delete "$INSTDIR\mpcdec.dll"
|
||||||
Delete "$INSTDIR\mpg123.dll"
|
Delete "$INSTDIR\mpg123.dll"
|
||||||
|
Delete "$INSTDIR\nghttp2.dll"
|
||||||
Delete "$INSTDIR\ogg.dll"
|
Delete "$INSTDIR\ogg.dll"
|
||||||
Delete "$INSTDIR\opus.dll"
|
Delete "$INSTDIR\opus.dll"
|
||||||
Delete "$INSTDIR\orc-0.4-0.dll"
|
Delete "$INSTDIR\orc-0.4-0.dll"
|
||||||
|
Delete "$INSTDIR\postproc-55.dll"
|
||||||
Delete "$INSTDIR\psl-5.dll"
|
Delete "$INSTDIR\psl-5.dll"
|
||||||
Delete "$INSTDIR\qtsparkle-qt6.dll"
|
Delete "$INSTDIR\qtsparkle-qt6.dll"
|
||||||
Delete "$INSTDIR\soup-2.4-1.dll"
|
Delete "$INSTDIR\soup-3.0-0.dll"
|
||||||
Delete "$INSTDIR\sqlite3.dll"
|
Delete "$INSTDIR\sqlite3.dll"
|
||||||
|
Delete "$INSTDIR\swresample-3.dll"
|
||||||
|
Delete "$INSTDIR\swscale-5.dll"
|
||||||
Delete "$INSTDIR\tag.dll"
|
Delete "$INSTDIR\tag.dll"
|
||||||
Delete "$INSTDIR\vorbis.dll"
|
Delete "$INSTDIR\vorbis.dll"
|
||||||
Delete "$INSTDIR\vorbisfile.dll"
|
Delete "$INSTDIR\vorbisfile.dll"
|
||||||
Delete "$INSTDIR\wavpackdll.dll"
|
Delete "$INSTDIR\wavpackdll.dll"
|
||||||
|
|
||||||
!ifdef release
|
!ifdef release
|
||||||
|
Delete "$INSTDIR\freetype.dll"
|
||||||
Delete "$INSTDIR\libpng16.dll"
|
Delete "$INSTDIR\libpng16.dll"
|
||||||
Delete "$INSTDIR\libprotobuf.dll"
|
Delete "$INSTDIR\libprotobuf.dll"
|
||||||
Delete "$INSTDIR\libxml2.dll"
|
Delete "$INSTDIR\libxml2.dll"
|
||||||
|
Delete "$INSTDIR\pcre2-8.dll"
|
||||||
Delete "$INSTDIR\pcre2-16.dll"
|
Delete "$INSTDIR\pcre2-16.dll"
|
||||||
|
Delete "$INSTDIR\twolame.dll"
|
||||||
Delete "$INSTDIR\zlib.dll"
|
Delete "$INSTDIR\zlib.dll"
|
||||||
!endif
|
!endif
|
||||||
!ifdef debug
|
!ifdef debug
|
||||||
|
Delete "$INSTDIR\freetyped.dll"
|
||||||
Delete "$INSTDIR\libpng16d.dll"
|
Delete "$INSTDIR\libpng16d.dll"
|
||||||
Delete "$INSTDIR\libprotobufd.dll"
|
Delete "$INSTDIR\libprotobufd.dll"
|
||||||
Delete "$INSTDIR\libxml2d.dll"
|
Delete "$INSTDIR\libxml2d.dll"
|
||||||
|
Delete "$INSTDIR\pcre2-8d.dll"
|
||||||
Delete "$INSTDIR\pcre2-16d.dll"
|
Delete "$INSTDIR\pcre2-16d.dll"
|
||||||
|
Delete "$INSTDIR\twolamed.dll"
|
||||||
Delete "$INSTDIR\zlibd.dll"
|
Delete "$INSTDIR\zlibd.dll"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
@@ -865,7 +943,11 @@ Section "Uninstall"
|
|||||||
|
|
||||||
; Common files
|
; Common files
|
||||||
|
|
||||||
|
Delete "$INSTDIR\icudt72.dll"
|
||||||
|
Delete "$INSTDIR\libfftw3-3.dll"
|
||||||
!ifdef msvc && debug
|
!ifdef msvc && debug
|
||||||
|
Delete "$INSTDIR\icuin72d.dll"
|
||||||
|
Delete "$INSTDIR\icuuc72d.dll"
|
||||||
Delete "$INSTDIR\Qt6Concurrentd.dll"
|
Delete "$INSTDIR\Qt6Concurrentd.dll"
|
||||||
Delete "$INSTDIR\Qt6Cored.dll"
|
Delete "$INSTDIR\Qt6Cored.dll"
|
||||||
Delete "$INSTDIR\Qt6Guid.dll"
|
Delete "$INSTDIR\Qt6Guid.dll"
|
||||||
@@ -873,6 +955,8 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\Qt6Sqld.dll"
|
Delete "$INSTDIR\Qt6Sqld.dll"
|
||||||
Delete "$INSTDIR\Qt6Widgetsd.dll"
|
Delete "$INSTDIR\Qt6Widgetsd.dll"
|
||||||
!else
|
!else
|
||||||
|
Delete "$INSTDIR\icuin72.dll"
|
||||||
|
Delete "$INSTDIR\icuuc72.dll"
|
||||||
Delete "$INSTDIR\Qt6Concurrent.dll"
|
Delete "$INSTDIR\Qt6Concurrent.dll"
|
||||||
Delete "$INSTDIR\Qt6Core.dll"
|
Delete "$INSTDIR\Qt6Core.dll"
|
||||||
Delete "$INSTDIR\Qt6Gui.dll"
|
Delete "$INSTDIR\Qt6Gui.dll"
|
||||||
@@ -893,6 +977,7 @@ Section "Uninstall"
|
|||||||
!ifdef msvc && debug
|
!ifdef msvc && debug
|
||||||
Delete "$INSTDIR\platforms\qwindowsd.dll"
|
Delete "$INSTDIR\platforms\qwindowsd.dll"
|
||||||
Delete "$INSTDIR\styles\qwindowsvistastyled.dll"
|
Delete "$INSTDIR\styles\qwindowsvistastyled.dll"
|
||||||
|
Delete "$INSTDIR\tls\qschannelbackendd.dll"
|
||||||
Delete "$INSTDIR\tls\qopensslbackendd.dll"
|
Delete "$INSTDIR\tls\qopensslbackendd.dll"
|
||||||
Delete "$INSTDIR\sqldrivers\qsqlited.dll"
|
Delete "$INSTDIR\sqldrivers\qsqlited.dll"
|
||||||
Delete "$INSTDIR\imageformats\qgifd.dll"
|
Delete "$INSTDIR\imageformats\qgifd.dll"
|
||||||
@@ -901,6 +986,7 @@ Section "Uninstall"
|
|||||||
!else
|
!else
|
||||||
Delete "$INSTDIR\platforms\qwindows.dll"
|
Delete "$INSTDIR\platforms\qwindows.dll"
|
||||||
Delete "$INSTDIR\styles\qwindowsvistastyle.dll"
|
Delete "$INSTDIR\styles\qwindowsvistastyle.dll"
|
||||||
|
Delete "$INSTDIR\tls\qschannelbackend.dll"
|
||||||
Delete "$INSTDIR\tls\qopensslbackend.dll"
|
Delete "$INSTDIR\tls\qopensslbackend.dll"
|
||||||
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
|
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
|
||||||
Delete "$INSTDIR\imageformats\qgif.dll"
|
Delete "$INSTDIR\imageformats\qgif.dll"
|
||||||
@@ -926,7 +1012,6 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\gstreamer-plugins\libgstaudiotestsrc.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudiotestsrc.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstautodetect.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstautodetect.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstbs2b.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstbs2b.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstcdio.dll"
|
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstcoreelements.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstcoreelements.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstdash.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstdash.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstdirectsound.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstdirectsound.dll"
|
||||||
@@ -936,9 +1021,11 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\gstreamer-plugins\libgstfdkaac.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstfdkaac.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstflac.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstflac.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstgio.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstgio.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstgme.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgsthls.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgsthls.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgsticydemux.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgsticydemux.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstid3demux.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstid3demux.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstid3tag.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstisomp4.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstisomp4.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstlame.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstlame.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstlibav.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstlibav.dll"
|
||||||
@@ -958,11 +1045,13 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\gstreamer-plugins\libgstspeex.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstspeex.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgsttaglib.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgsttaglib.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgsttcp.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgsttcp.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgsttwolame.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgsttypefindfunctions.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgsttypefindfunctions.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstudp.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstudp.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstvolume.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstvolume.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstvorbis.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstvorbis.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstwasapi.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstwasapi.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstwavenc.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstwavpack.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstwavpack.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstwavparse.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstwavparse.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\libgstxingmux.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstxingmux.dll"
|
||||||
@@ -971,6 +1060,7 @@ Section "Uninstall"
|
|||||||
; MSVC GStreamer plugins
|
; MSVC GStreamer plugins
|
||||||
|
|
||||||
!ifdef msvc
|
!ifdef msvc
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstaes.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstaiff.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstaiff.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstapetag.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstapetag.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstapp.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstapp.dll"
|
||||||
@@ -994,31 +1084,37 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\gstreamer-plugins\gstfdkaac.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstfdkaac.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstflac.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstflac.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstgio.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstgio.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstgme.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gsthls.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gsthls.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gsticydemux.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gsticydemux.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstid3demux.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstid3demux.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstid3tag.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstisomp4.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstisomp4.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstlame.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstlame.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstlibav.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstmpg123.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstmpg123.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstmusepack.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstmusepack.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstogg.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstogg.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstopenmpt.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstopenmpt.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstopus.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstopus.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstopusparse.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstopusparse.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstpbtypes.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstplayback.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstplayback.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstreplaygain.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstreplaygain.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstrtp.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstrtp.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstrtsp.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstrtsp.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstspeex.dll"
|
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstsoup.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstsoup.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstspectrum.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstspectrum.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstspeex.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gsttaglib.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gsttcp.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gsttcp.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gsttwolame.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gsttypefindfunctions.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gsttypefindfunctions.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstudp.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstudp.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstvolume.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstvolume.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstvorbis.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstvorbis.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstwasapi.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstwasapi.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstwasapi2.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstwavenc.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstwavpack.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstwavpack.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstwavparse.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstwavparse.dll"
|
||||||
Delete "$INSTDIR\gstreamer-plugins\gstxingmux.dll"
|
Delete "$INSTDIR\gstreamer-plugins\gstxingmux.dll"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.7)
|
||||||
|
|
||||||
set(SOURCES gstfastspectrum.cpp gstmoodbarplugin.cpp)
|
set(SOURCES gstfastspectrum.cpp gstmoodbarplugin.cpp)
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,10 @@ enum {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
#define gst_fastspectrum_parent_class parent_class
|
#define gst_fastspectrum_parent_class parent_class
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||||
G_DEFINE_TYPE(GstFastSpectrum, gst_fastspectrum, GST_TYPE_AUDIO_FILTER)
|
G_DEFINE_TYPE(GstFastSpectrum, gst_fastspectrum, GST_TYPE_AUDIO_FILTER)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
static void gst_fastspectrum_finalize(GObject *object);
|
static void gst_fastspectrum_finalize(GObject *object);
|
||||||
static void gst_fastspectrum_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
|
static void gst_fastspectrum_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
|
||||||
@@ -79,9 +82,9 @@ static void gst_fastspectrum_class_init(GstFastSpectrumClass *klass) {
|
|||||||
|
|
||||||
filter_class->setup = GST_DEBUG_FUNCPTR(gst_fastspectrum_setup);
|
filter_class->setup = GST_DEBUG_FUNCPTR(gst_fastspectrum_setup);
|
||||||
|
|
||||||
g_object_class_install_property(gobject_class, PROP_INTERVAL, g_param_spec_uint64("interval", "Interval", "Interval of time between message posts (in nanoseconds)", 1, G_MAXUINT64, DEFAULT_INTERVAL, GParamFlags(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
g_object_class_install_property(gobject_class, PROP_INTERVAL, g_param_spec_uint64("interval", "Interval", "Interval of time between message posts (in nanoseconds)", 1, G_MAXUINT64, DEFAULT_INTERVAL, static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||||
|
|
||||||
g_object_class_install_property(gobject_class, PROP_BANDS, g_param_spec_uint("bands", "Bands", "Number of frequency bands", 0, G_MAXUINT, DEFAULT_BANDS, GParamFlags(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
g_object_class_install_property(gobject_class, PROP_BANDS, g_param_spec_uint("bands", "Bands", "Number of frequency bands", 0, G_MAXUINT, DEFAULT_BANDS, static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT(gst_fastspectrum_debug, "spectrum", 0, "audio spectrum analyser element");
|
GST_DEBUG_CATEGORY_INIT(gst_fastspectrum_debug, "spectrum", 0, "audio spectrum analyser element");
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class QMutex;
|
|||||||
|
|
||||||
typedef void (*GstFastSpectrumInputData)(const guint8 *in, double *out, guint len, double max_value, guint op, guint nfft);
|
typedef void (*GstFastSpectrumInputData)(const guint8 *in, double *out, guint len, double max_value, guint op, guint nfft);
|
||||||
|
|
||||||
typedef std::function<void(double *magnitudes, int size)> OutputCallback;
|
using OutputCallback = std::function<void(double *magnitudes, int size)>;
|
||||||
|
|
||||||
struct GstFastSpectrum {
|
struct GstFastSpectrum {
|
||||||
GstAudioFilter parent;
|
GstAudioFilter parent;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.7)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
core/logging.cpp
|
core/logging.cpp
|
||||||
|
|||||||
@@ -126,7 +126,8 @@ class LoggedDebug : public DebugBase<LoggedDebug> {
|
|||||||
static void MessageHandler(QtMsgType type, const QMessageLogContext&, const QString &message) {
|
static void MessageHandler(QtMsgType type, const QMessageLogContext&, const QString &message) {
|
||||||
|
|
||||||
if (message.startsWith(kMessageHandlerMagic)) {
|
if (message.startsWith(kMessageHandlerMagic)) {
|
||||||
fprintf(type == QtCriticalMsg || type == QtFatalMsg ? stderr : stdout, "%s\n", message.toUtf8().data() + kMessageHandlerMagicLength);
|
QByteArray message_data = message.toUtf8();
|
||||||
|
fprintf(type == QtCriticalMsg || type == QtFatalMsg ? stderr : stdout, "%s\n", message_data.constData() + kMessageHandlerMagicLength);
|
||||||
fflush(type == QtCriticalMsg || type == QtFatalMsg ? stderr : stdout);
|
fflush(type == QtCriticalMsg || type == QtFatalMsg ? stderr : stdout);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ void _MessageHandlerBase::DeviceReadyRead() {
|
|||||||
void _MessageHandlerBase::WriteMessage(const QByteArray &data) {
|
void _MessageHandlerBase::WriteMessage(const QByteArray &data) {
|
||||||
|
|
||||||
QDataStream s(device_);
|
QDataStream s(device_);
|
||||||
s << quint32(data.length());
|
s << static_cast<quint32>(data.length());
|
||||||
s.writeRawData(data.data(), static_cast<int>(data.length()));
|
s.writeRawData(data.data(), static_cast<int>(data.length()));
|
||||||
|
|
||||||
// Sorry.
|
// Sorry.
|
||||||
|
|||||||
@@ -35,9 +35,6 @@
|
|||||||
|
|
||||||
class QIODevice;
|
class QIODevice;
|
||||||
|
|
||||||
#define QStringFromStdString(x) QString::fromUtf8((x).data(), (x).size())
|
|
||||||
#define DataCommaSizeFromQString(x) (x).toUtf8().constData(), (x).toUtf8().length()
|
|
||||||
|
|
||||||
// Reads and writes uint32 length encoded protobufs to a socket.
|
// Reads and writes uint32 length encoded protobufs to a socket.
|
||||||
// This base QObject is separate from AbstractMessageHandler because moc can't handle templated classes.
|
// This base QObject is separate from AbstractMessageHandler because moc can't handle templated classes.
|
||||||
// Use AbstractMessageHandler instead.
|
// Use AbstractMessageHandler instead.
|
||||||
@@ -85,8 +82,8 @@ class AbstractMessageHandler : public _MessageHandlerBase {
|
|||||||
AbstractMessageHandler(QIODevice *device, QObject *parent);
|
AbstractMessageHandler(QIODevice *device, QObject *parent);
|
||||||
~AbstractMessageHandler() override { AbstractMessageHandler::AbortAll(); }
|
~AbstractMessageHandler() override { AbstractMessageHandler::AbortAll(); }
|
||||||
|
|
||||||
typedef MT MessageType;
|
using MessageType = MT;
|
||||||
typedef MessageReply<MT> ReplyType;
|
using ReplyType = MessageReply<MT>;
|
||||||
|
|
||||||
// Serialises the message and writes it to the socket.
|
// Serialises the message and writes it to the socket.
|
||||||
// This version MUST be called from the thread in which the AbstractMessageHandler was created.
|
// This version MUST be called from the thread in which the AbstractMessageHandler was created.
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ class WorkerPool : public _WorkerPoolBase {
|
|||||||
explicit WorkerPool(QObject *parent = nullptr);
|
explicit WorkerPool(QObject *parent = nullptr);
|
||||||
~WorkerPool() override;
|
~WorkerPool() override;
|
||||||
|
|
||||||
typedef typename HandlerType::MessageType MessageType;
|
using MessageType = typename HandlerType::MessageType;
|
||||||
typedef typename HandlerType::ReplyType ReplyType;
|
using ReplyType = typename HandlerType::ReplyType;
|
||||||
|
|
||||||
// Sets the name of the worker executable. This is looked for first in the current directory, and then in $PATH.
|
// Sets the name of the worker executable. This is looked for first in the current directory, and then in $PATH.
|
||||||
// You must call this before calling Start().
|
// You must call this before calling Start().
|
||||||
@@ -243,6 +243,10 @@ void WorkerPool<HandlerType>::DoStart() {
|
|||||||
|
|
||||||
QStringList search_path;
|
QStringList search_path;
|
||||||
search_path << QCoreApplication::applicationDirPath();
|
search_path << QCoreApplication::applicationDirPath();
|
||||||
|
#if defined(Q_OS_UNIX)
|
||||||
|
search_path << "/usr/libexec";
|
||||||
|
search_path << "/usr/local/libexec";
|
||||||
|
#endif
|
||||||
#if defined(Q_OS_MACOS) && defined(USE_BUNDLE)
|
#if defined(Q_OS_MACOS) && defined(USE_BUNDLE)
|
||||||
search_path << QCoreApplication::applicationDirPath() + "/" + USE_BUNDLE_DIR;
|
search_path << QCoreApplication::applicationDirPath() + "/" + USE_BUNDLE_DIR;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.7)
|
||||||
|
|
||||||
set(MESSAGES tagreadermessages.proto)
|
set(MESSAGES tagreadermessages.proto)
|
||||||
set(SOURCES tagreaderbase.cpp)
|
set(SOURCES tagreaderbase.cpp)
|
||||||
|
|
||||||
if(USE_TAGLIB AND TAGLIB_FOUND)
|
if(USE_TAGLIB AND TAGLIB_FOUND)
|
||||||
list(APPEND SOURCES tagreadertaglib.cpp)
|
list(APPEND SOURCES tagreadertaglib.cpp tagreadergme.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(USE_TAGPARSER AND TAGPARSER_FOUND)
|
if(USE_TAGPARSER AND TAGPARSER_FOUND)
|
||||||
|
|||||||
@@ -25,3 +25,33 @@ const std::string TagReaderBase::kEmbeddedCover = "(embedded)";
|
|||||||
|
|
||||||
TagReaderBase::TagReaderBase() = default;
|
TagReaderBase::TagReaderBase() = default;
|
||||||
TagReaderBase::~TagReaderBase() = default;
|
TagReaderBase::~TagReaderBase() = default;
|
||||||
|
|
||||||
|
void TagReaderBase::Decode(const QString &tag, std::string *output) {
|
||||||
|
|
||||||
|
output->assign(DataCommaSizeFromQString(tag));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
float TagReaderBase::ConvertPOPMRating(const int POPM_rating) {
|
||||||
|
|
||||||
|
if (POPM_rating < 0x01) return 0.0F;
|
||||||
|
else if (POPM_rating < 0x40) return 0.20F;
|
||||||
|
else if (POPM_rating < 0x80) return 0.40F;
|
||||||
|
else if (POPM_rating < 0xC0) return 0.60F;
|
||||||
|
else if (POPM_rating < 0xFC) return 0.80F;
|
||||||
|
|
||||||
|
return 1.0F;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int TagReaderBase::ConvertToPOPMRating(const float rating) {
|
||||||
|
|
||||||
|
if (rating < 0.20) return 0x00;
|
||||||
|
else if (rating < 0.40) return 0x01;
|
||||||
|
else if (rating < 0.60) return 0x40;
|
||||||
|
else if (rating < 0.80) return 0x80;
|
||||||
|
else if (rating < 1.0) return 0xC0;
|
||||||
|
|
||||||
|
return 0xFF;
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,6 +27,9 @@
|
|||||||
|
|
||||||
#include "tagreadermessages.pb.h"
|
#include "tagreadermessages.pb.h"
|
||||||
|
|
||||||
|
#define QStringFromStdString(x) QString::fromUtf8((x).data(), (x).size())
|
||||||
|
#define DataCommaSizeFromQString(x) (x).toUtf8().constData(), (x).toUtf8().length()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This class holds all useful methods to read and write tags from/to files.
|
* This class holds all useful methods to read and write tags from/to files.
|
||||||
* You should not use it directly in the main process but rather use a TagReaderWorker process (using TagReaderClient)
|
* You should not use it directly in the main process but rather use a TagReaderWorker process (using TagReaderClient)
|
||||||
@@ -38,7 +41,7 @@ class TagReaderBase {
|
|||||||
|
|
||||||
virtual bool IsMediaFile(const QString &filename) const = 0;
|
virtual bool IsMediaFile(const QString &filename) const = 0;
|
||||||
|
|
||||||
virtual void ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const = 0;
|
virtual bool ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const = 0;
|
||||||
virtual bool SaveFile(const QString &filename, const spb::tagreader::SongMetadata &song) const = 0;
|
virtual bool SaveFile(const QString &filename, const spb::tagreader::SongMetadata &song) const = 0;
|
||||||
|
|
||||||
virtual QByteArray LoadEmbeddedArt(const QString &filename) const = 0;
|
virtual QByteArray LoadEmbeddedArt(const QString &filename) const = 0;
|
||||||
@@ -47,6 +50,11 @@ class TagReaderBase {
|
|||||||
virtual bool SaveSongPlaycountToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const = 0;
|
virtual bool SaveSongPlaycountToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const = 0;
|
||||||
virtual bool SaveSongRatingToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const = 0;
|
virtual bool SaveSongRatingToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const = 0;
|
||||||
|
|
||||||
|
static void Decode(const QString &tag, std::string *output);
|
||||||
|
|
||||||
|
static float ConvertPOPMRating(const int POPM_rating);
|
||||||
|
static int ConvertToPOPMRating(const float rating);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static const std::string kEmbeddedCover;
|
static const std::string kEmbeddedCover;
|
||||||
|
|
||||||
|
|||||||
299
ext/libstrawberry-tagreader/tagreadergme.cpp
Normal file
299
ext/libstrawberry-tagreader/tagreadergme.cpp
Normal file
@@ -0,0 +1,299 @@
|
|||||||
|
/*
|
||||||
|
* Strawberry Music Player
|
||||||
|
* Copyright 2022, Eoin O'Neill <eoinoneill1991@gmail.com>
|
||||||
|
*
|
||||||
|
* Strawberry 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.
|
||||||
|
*
|
||||||
|
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tagreadergme.h"
|
||||||
|
|
||||||
|
#include <tag.h>
|
||||||
|
#include <apefile.h>
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QString>
|
||||||
|
#include <QChar>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTextStream>
|
||||||
|
|
||||||
|
#include "utilities/timeconstants.h"
|
||||||
|
#include "core/logging.h"
|
||||||
|
#include "core/messagehandler.h"
|
||||||
|
#include "tagreaderbase.h"
|
||||||
|
#include "tagreadertaglib.h"
|
||||||
|
|
||||||
|
bool GME::IsSupportedFormat(const QFileInfo &file_info) {
|
||||||
|
return file_info.exists() && (file_info.completeSuffix().endsWith("spc", Qt::CaseInsensitive) || file_info.completeSuffix().endsWith("vgm"), Qt::CaseInsensitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GME::ReadFile(const QFileInfo &file_info, spb::tagreader::SongMetadata *song_info) {
|
||||||
|
|
||||||
|
if (file_info.completeSuffix().endsWith("spc"), Qt::CaseInsensitive) {
|
||||||
|
SPC::Read(file_info, song_info);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (file_info.completeSuffix().endsWith("vgm", Qt::CaseInsensitive)) {
|
||||||
|
VGM::Read(file_info, song_info);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 GME::UnpackBytes32(const char *const bytes, size_t length) {
|
||||||
|
|
||||||
|
Q_ASSERT(length <= 4 && length > 0);
|
||||||
|
|
||||||
|
quint32 value = 0;
|
||||||
|
for (size_t i = 0; i < length; i++) {
|
||||||
|
value |= static_cast<unsigned char>(bytes[i]) << (8 * i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GME::SPC::Read(const QFileInfo &file_info, spb::tagreader::SongMetadata *song_info) {
|
||||||
|
|
||||||
|
QFile file(file_info.filePath());
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) return;
|
||||||
|
|
||||||
|
qLog(Debug) << "Reading tags from SPC file" << file_info.fileName();
|
||||||
|
|
||||||
|
// Check for header -- more reliable than file name alone.
|
||||||
|
if (!file.read(33).startsWith(QString("SNES-SPC700").toLatin1())) return;
|
||||||
|
|
||||||
|
// First order of business -- get any tag values that exist within the core file information.
|
||||||
|
// These only allow for a certain number of bytes per field,
|
||||||
|
// so they will likely be overwritten either by the id666 standard or the APETAG format (as used by other players, such as foobar and winamp)
|
||||||
|
//
|
||||||
|
// Make sure to check id6 documentation before changing the read values!
|
||||||
|
|
||||||
|
file.seek(HAS_ID6_OFFSET);
|
||||||
|
bool has_id6 = (file.read(1)[0] == static_cast<char>(xID6_STATUS::ON));
|
||||||
|
|
||||||
|
file.seek(SONG_TITLE_OFFSET);
|
||||||
|
song_info->set_title(QString::fromLatin1(file.read(32)).toStdString());
|
||||||
|
|
||||||
|
file.seek(GAME_TITLE_OFFSET);
|
||||||
|
song_info->set_album(QString::fromLatin1(file.read(32)).toStdString());
|
||||||
|
|
||||||
|
file.seek(ARTIST_OFFSET);
|
||||||
|
song_info->set_artist(QString::fromLatin1(file.read(32)).toStdString());
|
||||||
|
|
||||||
|
file.seek(INTRO_LENGTH_OFFSET);
|
||||||
|
QByteArray length_bytes = file.read(INTRO_LENGTH_SIZE);
|
||||||
|
quint64 length_in_sec = 0;
|
||||||
|
if (length_bytes.size() >= INTRO_LENGTH_SIZE) {
|
||||||
|
length_in_sec = ConvertSPCStringToNum(length_bytes);
|
||||||
|
|
||||||
|
if (!length_in_sec || length_in_sec >= 0x1FFF) {
|
||||||
|
// This means that parsing the length as a string failed, so get value LE.
|
||||||
|
length_in_sec = length_bytes[0] | (length_bytes[1] << 8) | (length_bytes[2] << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length_in_sec < 0x1FFF) {
|
||||||
|
song_info->set_length_nanosec(length_in_sec * kNsecPerSec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.seek(FADE_LENGTH_OFFSET);
|
||||||
|
QByteArray fade_bytes = file.read(FADE_LENGTH_SIZE);
|
||||||
|
if (fade_bytes.size() >= FADE_LENGTH_SIZE) {
|
||||||
|
quint64 fade_length_in_ms = ConvertSPCStringToNum(fade_bytes);
|
||||||
|
|
||||||
|
if (fade_length_in_ms > 0x7FFF) {
|
||||||
|
fade_length_in_ms = fade_bytes[0] | (fade_bytes[1] << 8) | (fade_bytes[2] << 16) | (fade_bytes[3] << 24);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for XID6 data -- this is infrequently used, but being able to fill in data from this is ideal before trying to rely on APETAG values.
|
||||||
|
// XID6 format follows EA's binary file format standard named "IFF"
|
||||||
|
file.seek(XID6_OFFSET);
|
||||||
|
if (has_id6 && file.read(4) == QString("xid6").toLatin1()) {
|
||||||
|
QByteArray xid6_head_data = file.read(4);
|
||||||
|
if (xid6_head_data.size() >= 4) {
|
||||||
|
qint64 xid6_size = xid6_head_data[0] | (xid6_head_data[1] << 8) | (xid6_head_data[2] << 16) | xid6_head_data[3];
|
||||||
|
// This should be the size remaining for entire ID6 block, but it seems that most files treat this as the size of the remaining header space...
|
||||||
|
|
||||||
|
qLog(Debug) << file_info.fileName() << "has ID6 tag.";
|
||||||
|
|
||||||
|
while ((file.pos()) + 4 < XID6_OFFSET + xid6_size) {
|
||||||
|
QByteArray arr = file.read(4);
|
||||||
|
if (arr.size() < 4) break;
|
||||||
|
|
||||||
|
qint8 id = arr[0];
|
||||||
|
qint8 type = arr[1];
|
||||||
|
Q_UNUSED(id);
|
||||||
|
Q_UNUSED(type);
|
||||||
|
qint16 length = arr[2] | (arr[3] << 8);
|
||||||
|
|
||||||
|
file.read(GetNextMemAddressAlign32bit(length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Music Players that support SPC tend to support additional tagging data as
|
||||||
|
// an APETAG entry at the bottom of the file instead of writing into the xid6 tagging space.
|
||||||
|
// This is where a lot of the extra data for a file is stored, such as genre or replaygain data.
|
||||||
|
// This data is currently supported by TagLib, so we will simply use that for the remaining values.
|
||||||
|
TagLib::APE::File ape(file_info.filePath().toStdString().data());
|
||||||
|
if (ape.hasAPETag()) {
|
||||||
|
TagLib::Tag *tag = ape.tag();
|
||||||
|
if (!tag) return;
|
||||||
|
|
||||||
|
TagReaderTagLib::Decode(tag->artist(), song_info->mutable_artist());
|
||||||
|
TagReaderTagLib::Decode(tag->album(), song_info->mutable_album());
|
||||||
|
TagReaderTagLib::Decode(tag->title(), song_info->mutable_title());
|
||||||
|
TagReaderTagLib::Decode(tag->genre(), song_info->mutable_genre());
|
||||||
|
song_info->set_track(tag->track());
|
||||||
|
song_info->set_year(tag->year());
|
||||||
|
}
|
||||||
|
|
||||||
|
song_info->set_valid(true);
|
||||||
|
song_info->set_filetype(spb::tagreader::SongMetadata_FileType_SPC);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
qint16 GME::SPC::GetNextMemAddressAlign32bit(qint16 input) {
|
||||||
|
return ((input + 0x3) & ~0x3);
|
||||||
|
// Plus 0x3 for rounding up (not down), AND NOT to flatten out on a 32 bit level.
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 GME::SPC::ConvertSPCStringToNum(const QByteArray &arr) {
|
||||||
|
|
||||||
|
quint64 result = 0;
|
||||||
|
for (auto it = arr.begin(); it != arr.end(); it++) {
|
||||||
|
unsigned int num = *it - '0';
|
||||||
|
if (num > 9) break;
|
||||||
|
result = (result * 10) + num; // Shift Left and add.
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GME::VGM::Read(const QFileInfo &file_info, spb::tagreader::SongMetadata *song_info) {
|
||||||
|
|
||||||
|
QFile file(file_info.filePath());
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) return;
|
||||||
|
|
||||||
|
qLog(Debug) << "Reading tags from VGM file" << file_info.fileName();
|
||||||
|
|
||||||
|
if (!file.read(4).startsWith(QString("Vgm ").toLatin1())) return;
|
||||||
|
|
||||||
|
file.seek(GD3_TAG_PTR);
|
||||||
|
QByteArray gd3_head = file.read(4);
|
||||||
|
if (gd3_head.size() < 4) return;
|
||||||
|
|
||||||
|
quint64 pt = GME::UnpackBytes32(gd3_head.constData(), gd3_head.size());
|
||||||
|
|
||||||
|
file.seek(SAMPLE_COUNT);
|
||||||
|
QByteArray sample_count_bytes = file.read(4);
|
||||||
|
file.seek(LOOP_SAMPLE_COUNT);
|
||||||
|
QByteArray loop_count_bytes = file.read(4);
|
||||||
|
quint64 length = 0;
|
||||||
|
|
||||||
|
if (!GetPlaybackLength(sample_count_bytes, loop_count_bytes, length)) return;
|
||||||
|
|
||||||
|
file.seek(GD3_TAG_PTR + pt);
|
||||||
|
QByteArray gd3_version = file.read(4);
|
||||||
|
|
||||||
|
file.seek(file.pos() + 4);
|
||||||
|
QByteArray gd3_length_bytes = file.read(4);
|
||||||
|
quint32 gd3_length = GME::UnpackBytes32(gd3_length_bytes.constData(), gd3_length_bytes.size());
|
||||||
|
|
||||||
|
QByteArray gd3Data = file.read(gd3_length);
|
||||||
|
QTextStream fileTagStream(gd3Data, QIODevice::ReadOnly);
|
||||||
|
// Stored as 16 bit UTF string, two bytes per letter.
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
fileTagStream.setEncoding(QStringConverter::Utf16);
|
||||||
|
#else
|
||||||
|
fileTagStream.setCodec("UTF-16");
|
||||||
|
#endif
|
||||||
|
QStringList strings = fileTagStream.readLine(0).split(QChar('\0'));
|
||||||
|
if (strings.count() < 10) return;
|
||||||
|
|
||||||
|
// VGM standard dictates string tag data exist in specific order.
|
||||||
|
// Order alternates between English and Japanese version of data.
|
||||||
|
// Read GD3 tag standard for more details.
|
||||||
|
song_info->set_title(strings[0].toStdString());
|
||||||
|
song_info->set_album(strings[2].toStdString());
|
||||||
|
song_info->set_artist(strings[6].toStdString());
|
||||||
|
song_info->set_year(strings[8].left(4).toInt());
|
||||||
|
song_info->set_length_nanosec(length * kNsecPerMsec);
|
||||||
|
song_info->set_valid(true);
|
||||||
|
song_info->set_filetype(spb::tagreader::SongMetadata_FileType_VGM);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GME::VGM::GetPlaybackLength(const QByteArray &sample_count_bytes, const QByteArray &loop_count_bytes, quint64 &out_length) {
|
||||||
|
|
||||||
|
if (sample_count_bytes.size() != 4) return false;
|
||||||
|
if (loop_count_bytes.size() != 4) return false;
|
||||||
|
|
||||||
|
quint64 sample_count = GME::UnpackBytes32(sample_count_bytes.constData(), sample_count_bytes.size());
|
||||||
|
|
||||||
|
if (sample_count <= 0) return false;
|
||||||
|
|
||||||
|
quint64 loop_sample_count = GME::UnpackBytes32(loop_count_bytes.constData(), loop_count_bytes.size());
|
||||||
|
|
||||||
|
if (loop_sample_count <= 0) {
|
||||||
|
out_length = sample_count * 1000 / SAMPLE_TIMEBASE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 intro_length_ms = (sample_count - loop_sample_count) * 1000 / SAMPLE_TIMEBASE;
|
||||||
|
quint64 loop_length_ms = (loop_sample_count) * 1000 / SAMPLE_TIMEBASE;
|
||||||
|
out_length = intro_length_ms + (loop_length_ms * 2) + GST_GME_LOOP_TIME_MS;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TagReaderGME::TagReaderGME() = default;
|
||||||
|
TagReaderGME::~TagReaderGME() = default;
|
||||||
|
|
||||||
|
bool TagReaderGME::IsMediaFile(const QString &filename) const {
|
||||||
|
QFileInfo fileinfo(filename);
|
||||||
|
return GME::IsSupportedFormat(fileinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TagReaderGME::ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const {
|
||||||
|
QFileInfo fileinfo(filename);
|
||||||
|
return GME::ReadFile(fileinfo, song);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TagReaderGME::SaveFile(const QString&, const spb::tagreader::SongMetadata&) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray TagReaderGME::LoadEmbeddedArt(const QString&) const {
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TagReaderGME::SaveEmbeddedArt(const QString&, const QByteArray&) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TagReaderGME::SaveSongPlaycountToFile(const QString&, const spb::tagreader::SongMetadata&) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TagReaderGME::SaveSongRatingToFile(const QString&, const spb::tagreader::SongMetadata&) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
111
ext/libstrawberry-tagreader/tagreadergme.h
Normal file
111
ext/libstrawberry-tagreader/tagreadergme.h
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Strawberry Music Player
|
||||||
|
* Copyright 2022, Eoin O'Neill <eoinoneill1991@gmail.com>
|
||||||
|
*
|
||||||
|
* Strawberry 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.
|
||||||
|
*
|
||||||
|
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TAGREADERGME_H
|
||||||
|
#define TAGREADERGME_H
|
||||||
|
|
||||||
|
#include <taglib/tstring.h>
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QString>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
#include "tagreaderbase.h"
|
||||||
|
#include "tagreadermessages.pb.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace GME {
|
||||||
|
bool IsSupportedFormat(const QFileInfo &file_info);
|
||||||
|
bool ReadFile(const QFileInfo &file_info, spb::tagreader::SongMetadata *song_info);
|
||||||
|
|
||||||
|
uint32_t UnpackBytes32(const char *const arr, size_t length);
|
||||||
|
|
||||||
|
namespace SPC {
|
||||||
|
// SPC SPEC: http://vspcplay.raphnet.net/spc_file_format.txt
|
||||||
|
|
||||||
|
constexpr int HAS_ID6_OFFSET = 0x23;
|
||||||
|
constexpr int SONG_TITLE_OFFSET = 0x2E;
|
||||||
|
constexpr int GAME_TITLE_OFFSET = 0x4E;
|
||||||
|
constexpr int DUMPER_OFFSET = 0x6E;
|
||||||
|
constexpr int COMMENTS_OFFSET = 0x7E;
|
||||||
|
// It seems that intro length and fade length are inconsistent from file to file.
|
||||||
|
// It should be looked into within the GME source code to see how GStreamer gets its values for playback length.
|
||||||
|
constexpr int INTRO_LENGTH_OFFSET = 0xA9;
|
||||||
|
constexpr int INTRO_LENGTH_SIZE = 3;
|
||||||
|
constexpr int FADE_LENGTH_OFFSET = 0xAC;
|
||||||
|
constexpr int FADE_LENGTH_SIZE = 4;
|
||||||
|
constexpr int ARTIST_OFFSET = 0xB1;
|
||||||
|
constexpr int XID6_OFFSET = (0x101C0 + 64);
|
||||||
|
|
||||||
|
constexpr int NANO_PER_MS = 1000000;
|
||||||
|
|
||||||
|
enum xID6_STATUS {
|
||||||
|
ON = 0x26,
|
||||||
|
OFF = 0x27,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum xID6_ID { SongName = 0x01, GameName = 0x02, ArtistName = 0x03 };
|
||||||
|
|
||||||
|
enum xID6_TYPE { Length = 0x0, String = 0x1, Integer = 0x4 };
|
||||||
|
|
||||||
|
void Read(const QFileInfo &file_info, spb::tagreader::SongMetadata *song_info);
|
||||||
|
qint16 GetNextMemAddressAlign32bit(qint16 input);
|
||||||
|
quint64 ConvertSPCStringToNum(const QByteArray &arr);
|
||||||
|
} // namespace SPC
|
||||||
|
|
||||||
|
namespace VGM {
|
||||||
|
// VGM SPEC:
|
||||||
|
// http://www.smspower.org/uploads/Music/vgmspec170.txt?sid=17c810c54633b6dd4982f92f718361c1
|
||||||
|
// GD3 TAG SPEC:
|
||||||
|
// http://www.smspower.org/uploads/Music/gd3spec100.txt
|
||||||
|
constexpr int GD3_TAG_PTR = 0x14;
|
||||||
|
constexpr int SAMPLE_COUNT = 0x18;
|
||||||
|
constexpr int LOOP_SAMPLE_COUNT = 0x20;
|
||||||
|
constexpr int SAMPLE_TIMEBASE = 44100;
|
||||||
|
constexpr int GST_GME_LOOP_TIME_MS = 8000;
|
||||||
|
|
||||||
|
void Read(const QFileInfo &file_info, spb::tagreader::SongMetadata *song_info);
|
||||||
|
// Takes in two QByteArrays, expected to be 4 bytes long. Desired length is returned via output parameter out_length. Returns false on error.
|
||||||
|
bool GetPlaybackLength(const QByteArray &sample_count_bytes, const QByteArray &loop_count_bytes, quint64 &out_length);
|
||||||
|
|
||||||
|
} // namespace VGM
|
||||||
|
|
||||||
|
} // namespace GME
|
||||||
|
|
||||||
|
// TagReaderGME
|
||||||
|
// Fulfills Strawberry's Intended interface for tag reading.
|
||||||
|
class TagReaderGME : public TagReaderBase {
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TagReaderGME();
|
||||||
|
~TagReaderGME();
|
||||||
|
|
||||||
|
bool IsMediaFile(const QString &filename) const override;
|
||||||
|
|
||||||
|
bool ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const override;
|
||||||
|
bool SaveFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
|
||||||
|
|
||||||
|
QByteArray LoadEmbeddedArt(const QString &filename) const override;
|
||||||
|
bool SaveEmbeddedArt(const QString &filename, const QByteArray &data) override;
|
||||||
|
|
||||||
|
bool SaveSongPlaycountToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
|
||||||
|
bool SaveSongRatingToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -27,6 +27,8 @@ message SongMetadata {
|
|||||||
S3M = 19;
|
S3M = 19;
|
||||||
XM = 20;
|
XM = 20;
|
||||||
IT = 21;
|
IT = 21;
|
||||||
|
SPC = 22;
|
||||||
|
VGM = 23;
|
||||||
CDDA = 90;
|
CDDA = 90;
|
||||||
STREAM = 91;
|
STREAM = 91;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <algorithm>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <taglib/taglib.h>
|
#include <taglib/taglib.h>
|
||||||
@@ -91,7 +92,7 @@
|
|||||||
|
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
#include "core/messagehandler.h"
|
#include "core/messagehandler.h"
|
||||||
#include "core/timeconstants.h"
|
#include "utilities/timeconstants.h"
|
||||||
|
|
||||||
class FileRefFactory {
|
class FileRefFactory {
|
||||||
public:
|
public:
|
||||||
@@ -185,7 +186,7 @@ spb::tagreader::SongMetadata_FileType TagReaderTagLib::GuessFileType(TagLib::Fil
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const {
|
bool TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const {
|
||||||
|
|
||||||
const QByteArray url(QUrl::fromLocalFile(filename).toEncoded());
|
const QByteArray url(QUrl::fromLocalFile(filename).toEncoded());
|
||||||
const QFileInfo fileinfo(filename);
|
const QFileInfo fileinfo(filename);
|
||||||
@@ -195,18 +196,23 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
|
|||||||
song->set_basefilename(DataCommaSizeFromQString(fileinfo.fileName()));
|
song->set_basefilename(DataCommaSizeFromQString(fileinfo.fileName()));
|
||||||
song->set_url(url.constData(), url.size());
|
song->set_url(url.constData(), url.size());
|
||||||
song->set_filesize(fileinfo.size());
|
song->set_filesize(fileinfo.size());
|
||||||
song->set_mtime(fileinfo.lastModified().isValid() ? fileinfo.lastModified().toSecsSinceEpoch() : 0);
|
song->set_mtime(fileinfo.lastModified().isValid() ? std::max(fileinfo.lastModified().toSecsSinceEpoch(), 0LL) : 0LL);
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
||||||
song->set_ctime(fileinfo.birthTime().isValid() ? fileinfo.birthTime().toSecsSinceEpoch() : fileinfo.lastModified().isValid() ? fileinfo.lastModified().toSecsSinceEpoch() : 0);
|
song->set_ctime(fileinfo.birthTime().isValid() ? std::max(fileinfo.birthTime().toSecsSinceEpoch(), 0LL) : fileinfo.lastModified().isValid() ? std::max(fileinfo.lastModified().toSecsSinceEpoch(), 0LL) : 0LL);
|
||||||
#else
|
#else
|
||||||
song->set_ctime(fileinfo.created().isValid() ? fileinfo.created().toSecsSinceEpoch() : fileinfo.lastModified().isValid() ? fileinfo.lastModified().toSecsSinceEpoch() : 0);
|
song->set_ctime(fileinfo.created().isValid() ? std::max(fileinfo.created().toSecsSinceEpoch(), 0LL) : fileinfo.lastModified().isValid() ? std::max(fileinfo.lastModified().toSecsSinceEpoch(), 0LL) : 0LL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (song->ctime() <= 0) {
|
||||||
|
song->set_ctime(song->mtime());
|
||||||
|
}
|
||||||
|
|
||||||
song->set_lastseen(QDateTime::currentDateTime().toSecsSinceEpoch());
|
song->set_lastseen(QDateTime::currentDateTime().toSecsSinceEpoch());
|
||||||
|
|
||||||
std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename));
|
std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename));
|
||||||
if (fileref->isNull()) {
|
if (fileref->isNull()) {
|
||||||
qLog(Info) << "TagLib hasn't been able to read" << filename << "file";
|
qLog(Info) << "TagLib hasn't been able to read" << filename << "file";
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
song->set_filetype(GuessFileType(fileref.get()));
|
song->set_filetype(GuessFileType(fileref.get()));
|
||||||
@@ -248,9 +254,7 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (TagLib::FLAC::File *file_flac = dynamic_cast<TagLib::FLAC::File *>(fileref->file())) {
|
if (TagLib::FLAC::File *file_flac = dynamic_cast<TagLib::FLAC::File *>(fileref->file())) {
|
||||||
|
|
||||||
song->set_bitdepth(file_flac->audioProperties()->bitsPerSample());
|
song->set_bitdepth(file_flac->audioProperties()->bitsPerSample());
|
||||||
|
|
||||||
if (file_flac->xiphComment()) {
|
if (file_flac->xiphComment()) {
|
||||||
ParseOggTag(file_flac->xiphComment()->fieldListMap(), &disc, &compilation, song);
|
ParseOggTag(file_flac->xiphComment()->fieldListMap(), &disc, &compilation, song);
|
||||||
TagLib::List<TagLib::FLAC::Picture*> pictures = file_flac->pictureList();
|
TagLib::List<TagLib::FLAC::Picture*> pictures = file_flac->pictureList();
|
||||||
@@ -293,15 +297,11 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
|
|||||||
// content group
|
// content group
|
||||||
if (!map["TIT1"].isEmpty()) Decode(map["TIT1"].front()->toString(), song->mutable_grouping());
|
if (!map["TIT1"].isEmpty()) Decode(map["TIT1"].front()->toString(), song->mutable_grouping());
|
||||||
|
|
||||||
// ID3v2: lead performer/soloist
|
|
||||||
if (!map["TPE1"].isEmpty()) Decode(map["TPE1"].front()->toString(), song->mutable_performer());
|
|
||||||
|
|
||||||
// original artist/performer
|
// original artist/performer
|
||||||
if (!map["TOPE"].isEmpty()) Decode(map["TOPE"].front()->toString(), song->mutable_performer());
|
if (!map["TOPE"].isEmpty()) Decode(map["TOPE"].front()->toString(), song->mutable_performer());
|
||||||
|
|
||||||
// Skip TPE1 (which is the artist) here because we already fetched it
|
// Skip TPE1 (which is the artist) here because we already fetched it
|
||||||
|
|
||||||
|
|
||||||
// non-standard: Apple, Microsoft
|
// non-standard: Apple, Microsoft
|
||||||
if (!map["TPE2"].isEmpty()) Decode(map["TPE2"].front()->toString(), song->mutable_albumartist());
|
if (!map["TPE2"].isEmpty()) Decode(map["TPE2"].front()->toString(), song->mutable_albumartist());
|
||||||
|
|
||||||
@@ -396,6 +396,10 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
|
|||||||
song->set_originalyear(TStringToQString(mp4_tag->item(kMP4_OriginalYear_ID).toStringList().toString('\n')).left(4).toInt());
|
song->set_originalyear(TStringToQString(mp4_tag->item(kMP4_OriginalYear_ID).toStringList().toString('\n')).left(4).toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mp4_tag->item("cpil").isValid()) {
|
||||||
|
song->set_compilation(mp4_tag->item("cpil").toBool());
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
TagLib::MP4::Item item = mp4_tag->item(kMP4_FMPS_Playcount_ID);
|
TagLib::MP4::Item item = mp4_tag->item(kMP4_FMPS_Playcount_ID);
|
||||||
if (item.isValid()) {
|
if (item.isValid()) {
|
||||||
@@ -511,6 +515,8 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
|
|||||||
if (song->bitrate() <= 0) { song->set_bitrate(-1); }
|
if (song->bitrate() <= 0) { song->set_bitrate(-1); }
|
||||||
if (song->lastplayed() <= 0) { song->set_lastplayed(-1); }
|
if (song->lastplayed() <= 0) { song->set_lastplayed(-1); }
|
||||||
|
|
||||||
|
return song->filetype() != spb::tagreader::SongMetadata_FileType_UNKNOWN;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TagReaderTagLib::Decode(const TagLib::String &tag, std::string *output) {
|
void TagReaderTagLib::Decode(const TagLib::String &tag, std::string *output) {
|
||||||
@@ -520,12 +526,6 @@ void TagReaderTagLib::Decode(const TagLib::String &tag, std::string *output) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TagReaderTagLib::Decode(const QString &tag, std::string *output) {
|
|
||||||
|
|
||||||
output->assign(DataCommaSizeFromQString(tag));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void TagReaderTagLib::ParseOggTag(const TagLib::Ogg::FieldListMap &map, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const {
|
void TagReaderTagLib::ParseOggTag(const TagLib::Ogg::FieldListMap &map, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const {
|
||||||
|
|
||||||
if (!map["COMPOSER"].isEmpty()) Decode(map["COMPOSER"].front(), song->mutable_composer());
|
if (!map["COMPOSER"].isEmpty()) Decode(map["COMPOSER"].front(), song->mutable_composer());
|
||||||
@@ -687,7 +687,7 @@ bool TagReaderTagLib::SaveFile(const QString &filename, const spb::tagreader::So
|
|||||||
tag->setItem("\251grp", TagLib::StringList(TagLib::String(song.grouping(), TagLib::String::UTF8)));
|
tag->setItem("\251grp", TagLib::StringList(TagLib::String(song.grouping(), TagLib::String::UTF8)));
|
||||||
tag->setItem("\251lyr", TagLib::StringList(TagLib::String(song.lyrics(), TagLib::String::UTF8)));
|
tag->setItem("\251lyr", TagLib::StringList(TagLib::String(song.lyrics(), TagLib::String::UTF8)));
|
||||||
tag->setItem("aART", TagLib::StringList(TagLib::String(song.albumartist(), TagLib::String::UTF8)));
|
tag->setItem("aART", TagLib::StringList(TagLib::String(song.albumartist(), TagLib::String::UTF8)));
|
||||||
tag->setItem("cpil", TagLib::StringList(song.compilation() ? "1" : "0"));
|
tag->setItem("cpil", TagLib::MP4::Item(song.compilation()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle all the files which have VorbisComments (Ogg, OPUS, ...) in the same way;
|
// Handle all the files which have VorbisComments (Ogg, OPUS, ...) in the same way;
|
||||||
@@ -1041,30 +1041,6 @@ TagLib::ID3v2::PopularimeterFrame *TagReaderTagLib::GetPOPMFrameFromTag(TagLib::
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float TagReaderTagLib::ConvertPOPMRating(const int POPM_rating) {
|
|
||||||
|
|
||||||
if (POPM_rating < 0x01) return 0.0F;
|
|
||||||
else if (POPM_rating < 0x40) return 0.20F;
|
|
||||||
else if (POPM_rating < 0x80) return 0.40F;
|
|
||||||
else if (POPM_rating < 0xC0) return 0.60F;
|
|
||||||
else if (POPM_rating < 0xFC) return 0.80F;
|
|
||||||
|
|
||||||
return 1.0F;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int TagReaderTagLib::ConvertToPOPMRating(const float rating) {
|
|
||||||
|
|
||||||
if (rating < 0.20) return 0x00;
|
|
||||||
else if (rating < 0.40) return 0x01;
|
|
||||||
else if (rating < 0.60) return 0x40;
|
|
||||||
else if (rating < 0.80) return 0x80;
|
|
||||||
else if (rating < 1.0) return 0xC0;
|
|
||||||
|
|
||||||
return 0xFF;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TagReaderTagLib::SaveSongPlaycountToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const {
|
bool TagReaderTagLib::SaveSongPlaycountToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const {
|
||||||
|
|
||||||
if (filename.isEmpty()) return false;
|
if (filename.isEmpty()) return false;
|
||||||
@@ -1088,14 +1064,14 @@ bool TagReaderTagLib::SaveSongPlaycountToFile(const QString &filename, const spb
|
|||||||
TagLib::APE::Tag *tag = wavpack_file->APETag(true);
|
TagLib::APE::Tag *tag = wavpack_file->APETag(true);
|
||||||
if (!tag) return false;
|
if (!tag) return false;
|
||||||
if (song.playcount() > 0) {
|
if (song.playcount() > 0) {
|
||||||
tag->setItem("FMPS_PlayCount", TagLib::APE::Item("FMPS_PlayCount", TagLib::String::number(static_cast<int>(song.playcount()))));
|
tag->setItem("FMPS_Playcount", TagLib::APE::Item("FMPS_Playcount", TagLib::String::number(static_cast<int>(song.playcount()))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (TagLib::APE::File *ape_file = dynamic_cast<TagLib::APE::File*>(fileref->file())) {
|
else if (TagLib::APE::File *ape_file = dynamic_cast<TagLib::APE::File*>(fileref->file())) {
|
||||||
TagLib::APE::Tag *tag = ape_file->APETag(true);
|
TagLib::APE::Tag *tag = ape_file->APETag(true);
|
||||||
if (!tag) return false;
|
if (!tag) return false;
|
||||||
if (song.playcount() > 0) {
|
if (song.playcount() > 0) {
|
||||||
tag->setItem("FMPS_PlayCount", TagLib::APE::Item("FMPS_PlayCount", TagLib::String::number(static_cast<int>(song.playcount()))));
|
tag->setItem("FMPS_Playcount", TagLib::APE::Item("FMPS_Playcount", TagLib::String::number(static_cast<int>(song.playcount()))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (TagLib::Ogg::XiphComment *xiph_comment = dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) {
|
else if (TagLib::Ogg::XiphComment *xiph_comment = dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) {
|
||||||
@@ -1110,7 +1086,7 @@ bool TagReaderTagLib::SaveSongPlaycountToFile(const QString &filename, const spb
|
|||||||
TagLib::ID3v2::Tag *tag = mpeg_file->ID3v2Tag(true);
|
TagLib::ID3v2::Tag *tag = mpeg_file->ID3v2Tag(true);
|
||||||
if (!tag) return false;
|
if (!tag) return false;
|
||||||
if (song.playcount() > 0) {
|
if (song.playcount() > 0) {
|
||||||
SetUserTextFrame("FMPS_PlayCount", QString::number(song.playcount()), tag);
|
SetUserTextFrame("FMPS_Playcount", QString::number(song.playcount()), tag);
|
||||||
TagLib::ID3v2::PopularimeterFrame *frame = GetPOPMFrameFromTag(tag);
|
TagLib::ID3v2::PopularimeterFrame *frame = GetPOPMFrameFromTag(tag);
|
||||||
if (frame) {
|
if (frame) {
|
||||||
frame->setCounter(song.playcount());
|
frame->setCounter(song.playcount());
|
||||||
@@ -1129,7 +1105,7 @@ bool TagReaderTagLib::SaveSongPlaycountToFile(const QString &filename, const spb
|
|||||||
TagLib::APE::Tag *tag = mpc_file->APETag(true);
|
TagLib::APE::Tag *tag = mpc_file->APETag(true);
|
||||||
if (!tag) return false;
|
if (!tag) return false;
|
||||||
if (song.playcount() > 0) {
|
if (song.playcount() > 0) {
|
||||||
tag->setItem("FMPS_PlayCount", TagLib::APE::Item("FMPS_PlayCount", TagLib::String::number(static_cast<int>(song.playcount()))));
|
tag->setItem("FMPS_Playcount", TagLib::APE::Item("FMPS_Playcount", TagLib::String::number(static_cast<int>(song.playcount()))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (TagLib::ASF::File *asf_file = dynamic_cast<TagLib::ASF::File*>(fileref->file())) {
|
else if (TagLib::ASF::File *asf_file = dynamic_cast<TagLib::ASF::File*>(fileref->file())) {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class TagReaderTagLib : public TagReaderBase {
|
|||||||
|
|
||||||
bool IsMediaFile(const QString &filename) const override;
|
bool IsMediaFile(const QString &filename) const override;
|
||||||
|
|
||||||
void ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const override;
|
bool ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const override;
|
||||||
bool SaveFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
|
bool SaveFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
|
||||||
|
|
||||||
QByteArray LoadEmbeddedArt(const QString &filename) const override;
|
QByteArray LoadEmbeddedArt(const QString &filename) const override;
|
||||||
@@ -59,12 +59,11 @@ class TagReaderTagLib : public TagReaderBase {
|
|||||||
bool SaveSongPlaycountToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
|
bool SaveSongPlaycountToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
|
||||||
bool SaveSongRatingToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
|
bool SaveSongRatingToFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
|
||||||
|
|
||||||
|
static void Decode(const TagLib::String &tag, std::string *output);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
spb::tagreader::SongMetadata_FileType GuessFileType(TagLib::FileRef *fileref) const;
|
spb::tagreader::SongMetadata_FileType GuessFileType(TagLib::FileRef *fileref) const;
|
||||||
|
|
||||||
static void Decode(const TagLib::String &tag, std::string *output);
|
|
||||||
static void Decode(const QString &tag, std::string *output);
|
|
||||||
|
|
||||||
void ParseOggTag(const TagLib::Ogg::FieldListMap &map, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const;
|
void ParseOggTag(const TagLib::Ogg::FieldListMap &map, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const;
|
||||||
void ParseAPETag(const TagLib::APE::ItemListMap &map, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const;
|
void ParseAPETag(const TagLib::APE::ItemListMap &map, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const;
|
||||||
|
|
||||||
@@ -79,8 +78,6 @@ class TagReaderTagLib : public TagReaderBase {
|
|||||||
|
|
||||||
QByteArray LoadEmbeddedAPEArt(const TagLib::APE::ItemListMap &map) const;
|
QByteArray LoadEmbeddedAPEArt(const TagLib::APE::ItemListMap &map) const;
|
||||||
|
|
||||||
static float ConvertPOPMRating(const int POPM_rating);
|
|
||||||
static int ConvertToPOPMRating(const float rating);
|
|
||||||
static TagLib::ID3v2::PopularimeterFrame *GetPOPMFrameFromTag(TagLib::ID3v2::Tag *tag);
|
static TagLib::ID3v2::PopularimeterFrame *GetPOPMFrameFromTag(TagLib::ID3v2::Tag *tag);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -93,25 +93,30 @@ bool TagReaderTagParser::IsMediaFile(const QString &filename) const {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const {
|
bool TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const {
|
||||||
|
|
||||||
qLog(Debug) << "Reading tags from" << filename;
|
qLog(Debug) << "Reading tags from" << filename;
|
||||||
|
|
||||||
const QFileInfo fileinfo(filename);
|
const QFileInfo fileinfo(filename);
|
||||||
|
|
||||||
if (!fileinfo.exists() || fileinfo.suffix().compare("bak", Qt::CaseInsensitive) == 0) return;
|
if (!fileinfo.exists() || fileinfo.suffix().compare("bak", Qt::CaseInsensitive) == 0) return false;
|
||||||
|
|
||||||
const QByteArray url(QUrl::fromLocalFile(filename).toEncoded());
|
const QByteArray url(QUrl::fromLocalFile(filename).toEncoded());
|
||||||
|
|
||||||
song->set_basefilename(DataCommaSizeFromQString(fileinfo.fileName()));
|
song->set_basefilename(DataCommaSizeFromQString(fileinfo.fileName()));
|
||||||
song->set_url(url.constData(), url.size());
|
song->set_url(url.constData(), url.size());
|
||||||
song->set_filesize(fileinfo.size());
|
song->set_filesize(fileinfo.size());
|
||||||
song->set_mtime(fileinfo.lastModified().isValid() ? fileinfo.lastModified().toSecsSinceEpoch() : 0);
|
song->set_mtime(fileinfo.lastModified().isValid() ? std::max(fileinfo.lastModified().toSecsSinceEpoch(), 0LL) : 0LL);
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
||||||
song->set_ctime(fileinfo.birthTime().isValid() ? fileinfo.birthTime().toSecsSinceEpoch() : fileinfo.lastModified().isValid() ? fileinfo.lastModified().toSecsSinceEpoch() : 0);
|
song->set_ctime(fileinfo.birthTime().isValid() ? std::max(fileinfo.birthTime().toSecsSinceEpoch(), 0LL) : fileinfo.lastModified().isValid() ? std::max(fileinfo.lastModified().toSecsSinceEpoch(), 0LL) : 0LL);
|
||||||
#else
|
#else
|
||||||
song->set_ctime(fileinfo.created().isValid() ? fileinfo.created().toSecsSinceEpoch() : fileinfo.lastModified().isValid() ? fileinfo.lastModified().toSecsSinceEpoch() : 0);
|
song->set_ctime(fileinfo.created().isValid() ? std::max(fileinfo.created().toSecsSinceEpoch(), 0LL) : fileinfo.lastModified().isValid() ? std::max(fileinfo.lastModified().toSecsSinceEpoch(), 0LL) : 0LL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (song->ctime() <= 0) {
|
||||||
|
song->set_ctime(song->mtime());
|
||||||
|
}
|
||||||
|
|
||||||
song->set_lastseen(QDateTime::currentDateTime().toSecsSinceEpoch());
|
song->set_lastseen(QDateTime::currentDateTime().toSecsSinceEpoch());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -130,19 +135,19 @@ void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongM
|
|||||||
taginfo.parseContainerFormat(diag, progress);
|
taginfo.parseContainerFormat(diag, progress);
|
||||||
if (progress.isAborted()) {
|
if (progress.isAborted()) {
|
||||||
taginfo.close();
|
taginfo.close();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
taginfo.parseTracks(diag, progress);
|
taginfo.parseTracks(diag, progress);
|
||||||
if (progress.isAborted()) {
|
if (progress.isAborted()) {
|
||||||
taginfo.close();
|
taginfo.close();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
taginfo.parseTags(diag, progress);
|
taginfo.parseTags(diag, progress);
|
||||||
if (progress.isAborted()) {
|
if (progress.isAborted()) {
|
||||||
taginfo.close();
|
taginfo.close();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const TagParser::DiagMessage &msg : diag) {
|
for (const TagParser::DiagMessage &msg : diag) {
|
||||||
@@ -201,7 +206,7 @@ void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongM
|
|||||||
|
|
||||||
if (song->filetype() == spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_UNKNOWN) {
|
if (song->filetype() == spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_UNKNOWN) {
|
||||||
taginfo.close();
|
taginfo.close();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto tag : taginfo.tags()) {
|
for (const auto tag : taginfo.tags()) {
|
||||||
@@ -222,6 +227,10 @@ void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongM
|
|||||||
if (!tag->value(TagParser::KnownField::Cover).empty() && tag->value(TagParser::KnownField::Cover).dataSize() > 0) {
|
if (!tag->value(TagParser::KnownField::Cover).empty() && tag->value(TagParser::KnownField::Cover).dataSize() > 0) {
|
||||||
song->set_art_automatic(kEmbeddedCover);
|
song->set_art_automatic(kEmbeddedCover);
|
||||||
}
|
}
|
||||||
|
const float rating = ConvertPOPMRating(tag->value(TagParser::KnownField::Rating));
|
||||||
|
if (song->rating() <= 0 && rating > 0.0 && rating <= 1.0) {
|
||||||
|
song->set_rating(rating);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set integer fields to -1 if they're not valid
|
// Set integer fields to -1 if they're not valid
|
||||||
@@ -238,8 +247,12 @@ void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongM
|
|||||||
|
|
||||||
taginfo.close();
|
taginfo.close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(...) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
catch(...) {}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,7 +477,7 @@ bool TagReaderTagParser::SaveSongRatingToFile(const QString &filename, const spb
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const auto tag : taginfo.tags()) {
|
for (const auto tag : taginfo.tags()) {
|
||||||
tag->setValue(TagParser::KnownField::Rating, TagParser::TagValue(song.rating()));
|
tag->setValue(TagParser::KnownField::Rating, TagParser::TagValue(ConvertToPOPMRating(song.rating())));
|
||||||
}
|
}
|
||||||
taginfo.applyChanges(diag, progress);
|
taginfo.applyChanges(diag, progress);
|
||||||
taginfo.close();
|
taginfo.close();
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class TagReaderTagParser : public TagReaderBase {
|
|||||||
|
|
||||||
bool IsMediaFile(const QString &filename) const override;
|
bool IsMediaFile(const QString &filename) const override;
|
||||||
|
|
||||||
void ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const override;
|
bool ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const override;
|
||||||
bool SaveFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
|
bool SaveFile(const QString &filename, const spb::tagreader::SongMetadata &song) const override;
|
||||||
|
|
||||||
QByteArray LoadEmbeddedArt(const QString &filename) const override;
|
QByteArray LoadEmbeddedArt(const QString &filename) const override;
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ int main(int argc, char **argv) {
|
|||||||
qLog(Error) << "First line" << first_line << "does not match" << filepath;
|
qLog(Error) << "First line" << first_line << "does not match" << filepath;
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
QRegularExpression regexp(QStringLiteral("^\\t(.+) \\(compatibility version (\\d+\\.\\d+\\.\\d+), current version (\\d+\\.\\d+\\.\\d+)(, weak)?\\)$"));
|
QRegularExpression regexp(QStringLiteral("^\\t(.+) \\(compatibility version (\\d+\\.\\d+\\.\\d+), current version (\\d+\\.\\d+\\.\\d+)(, weak|, reexport)?\\)$"));
|
||||||
for (const QString &output_line : output_lines) {
|
for (const QString &output_line : output_lines) {
|
||||||
|
|
||||||
//qDebug() << "Final check on" << filepath << output_line;
|
//qDebug() << "Final check on" << filepath << output_line;
|
||||||
@@ -130,9 +130,6 @@ int main(int argc, char **argv) {
|
|||||||
else if (library.startsWith("/System/Library/") || library.startsWith("/usr/lib/")) { // System library
|
else if (library.startsWith("/System/Library/") || library.startsWith("/usr/lib/")) { // System library
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (library.endsWith("libgcc_s.1.dylib")) { // fftw points to it for some reason.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
qLog(Error) << "File" << filepath << "points to" << library;
|
qLog(Error) << "File" << filepath << "points to" << library;
|
||||||
success = false;
|
success = false;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.7)
|
||||||
|
|
||||||
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
|
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
|
|||||||
@@ -34,28 +34,11 @@ void TagReaderWorker::MessageArrived(const spb::tagreader::Message &message) {
|
|||||||
|
|
||||||
spb::tagreader::Message reply;
|
spb::tagreader::Message reply;
|
||||||
|
|
||||||
if (message.has_is_media_file_request()) {
|
bool success = HandleMessage(message, reply, &tag_reader_);
|
||||||
reply.mutable_is_media_file_response()->set_success(tag_reader_.IsMediaFile(QStringFromStdString(message.is_media_file_request().filename())));
|
if (!success) {
|
||||||
}
|
#if defined(USE_TAGLIB)
|
||||||
else if (message.has_read_file_request()) {
|
HandleMessage(message, reply, &tag_reader_gme_);
|
||||||
tag_reader_.ReadFile(QStringFromStdString(message.read_file_request().filename()), reply.mutable_read_file_response()->mutable_metadata());
|
#endif
|
||||||
}
|
|
||||||
else if (message.has_save_file_request()) {
|
|
||||||
reply.mutable_save_file_response()->set_success(tag_reader_.SaveFile(QStringFromStdString(message.save_file_request().filename()), message.save_file_request().metadata()));
|
|
||||||
}
|
|
||||||
else if (message.has_load_embedded_art_request()) {
|
|
||||||
QByteArray data = tag_reader_.LoadEmbeddedArt(QStringFromStdString(message.load_embedded_art_request().filename()));
|
|
||||||
reply.mutable_load_embedded_art_response()->set_data(data.constData(), data.size());
|
|
||||||
}
|
|
||||||
else if (message.has_save_embedded_art_request()) {
|
|
||||||
reply.mutable_save_embedded_art_response()->set_success(tag_reader_.SaveEmbeddedArt(QStringFromStdString(message.save_embedded_art_request().filename()), QByteArray(message.save_embedded_art_request().data().data(), static_cast<qint64>(message.save_embedded_art_request().data().size()))));
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (message.has_save_song_playcount_to_file_request()) {
|
|
||||||
reply.mutable_save_song_playcount_to_file_response()->set_success(tag_reader_.SaveSongPlaycountToFile(QStringFromStdString(message.save_song_playcount_to_file_request().filename()), message.save_song_playcount_to_file_request().metadata()));
|
|
||||||
}
|
|
||||||
else if (message.has_save_song_rating_to_file_request()) {
|
|
||||||
reply.mutable_save_song_rating_to_file_response()->set_success(tag_reader_.SaveSongRatingToFile(QStringFromStdString(message.save_song_rating_to_file_request().filename()), message.save_song_rating_to_file_request().metadata()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SendReply(message, &reply);
|
SendReply(message, &reply);
|
||||||
@@ -63,7 +46,50 @@ void TagReaderWorker::MessageArrived(const spb::tagreader::Message &message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TagReaderWorker::DeviceClosed() {
|
void TagReaderWorker::DeviceClosed() {
|
||||||
|
|
||||||
AbstractMessageHandler<spb::tagreader::Message>::DeviceClosed();
|
AbstractMessageHandler<spb::tagreader::Message>::DeviceClosed();
|
||||||
|
|
||||||
QCoreApplication::exit();
|
QCoreApplication::exit();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TagReaderWorker::HandleMessage(const spb::tagreader::Message &message, spb::tagreader::Message &reply, TagReaderBase *reader) {
|
||||||
|
|
||||||
|
if (message.has_is_media_file_request()) {
|
||||||
|
bool success = reader->IsMediaFile(QStringFromStdString(message.is_media_file_request().filename()));
|
||||||
|
reply.mutable_is_media_file_response()->set_success(success);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
else if (message.has_read_file_request()) {
|
||||||
|
bool success = reader->ReadFile(QStringFromStdString(message.read_file_request().filename()), reply.mutable_read_file_response()->mutable_metadata());
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
else if (message.has_save_file_request()) {
|
||||||
|
bool success = reader->SaveFile(QStringFromStdString(message.save_file_request().filename()), message.save_file_request().metadata());
|
||||||
|
reply.mutable_save_file_response()->set_success(success);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
else if (message.has_load_embedded_art_request()) {
|
||||||
|
QByteArray data = reader->LoadEmbeddedArt(QStringFromStdString(message.load_embedded_art_request().filename()));
|
||||||
|
reply.mutable_load_embedded_art_response()->set_data(data.constData(), data.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (message.has_save_embedded_art_request()) {
|
||||||
|
bool success = reader->SaveEmbeddedArt(QStringFromStdString(message.save_embedded_art_request().filename()), QByteArray(message.save_embedded_art_request().data().data(), static_cast<qint64>(message.save_embedded_art_request().data().size())));
|
||||||
|
reply.mutable_save_embedded_art_response()->set_success(success);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
else if (message.has_save_song_playcount_to_file_request()) {
|
||||||
|
bool success = reader->SaveSongPlaycountToFile(QStringFromStdString(message.save_song_playcount_to_file_request().filename()), message.save_song_playcount_to_file_request().metadata());
|
||||||
|
reply.mutable_save_song_playcount_to_file_response()->set_success(success);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
else if (message.has_save_song_rating_to_file_request()) {
|
||||||
|
bool success = reader->SaveSongRatingToFile(QStringFromStdString(message.save_song_rating_to_file_request().filename()), message.save_song_rating_to_file_request().metadata());
|
||||||
|
reply.mutable_save_song_rating_to_file_response()->set_success(success);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,9 +26,11 @@
|
|||||||
#include "core/messagehandler.h"
|
#include "core/messagehandler.h"
|
||||||
#if defined(USE_TAGLIB)
|
#if defined(USE_TAGLIB)
|
||||||
# include "tagreadertaglib.h"
|
# include "tagreadertaglib.h"
|
||||||
|
# include "tagreadergme.h"
|
||||||
#elif defined(USE_TAGPARSER)
|
#elif defined(USE_TAGPARSER)
|
||||||
# include "tagreadertagparser.h"
|
# include "tagreadertagparser.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "tagreadermessages.pb.h"
|
#include "tagreadermessages.pb.h"
|
||||||
|
|
||||||
class QIODevice;
|
class QIODevice;
|
||||||
@@ -44,8 +46,12 @@ class TagReaderWorker : public AbstractMessageHandler<spb::tagreader::Message> {
|
|||||||
void DeviceClosed() override;
|
void DeviceClosed() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Handle message using specific TagReaderBase implementation. Returns true on successful message handle.
|
||||||
|
bool HandleMessage(const spb::tagreader::Message &message, spb::tagreader::Message &reply, TagReaderBase* reader);
|
||||||
|
|
||||||
#if defined(USE_TAGLIB)
|
#if defined(USE_TAGLIB)
|
||||||
TagReaderTagLib tag_reader_;
|
TagReaderTagLib tag_reader_;
|
||||||
|
TagReaderGME tag_reader_gme_;
|
||||||
#elif defined(USE_TAGPARSER)
|
#elif defined(USE_TAGPARSER)
|
||||||
TagReaderTagParser tag_reader_;
|
TagReaderTagParser tag_reader_;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.7)
|
||||||
|
|
||||||
if(HAVE_TRANSLATIONS)
|
if(HAVE_TRANSLATIONS)
|
||||||
include(../cmake/Translations.cmake)
|
include(../cmake/Translations.cmake)
|
||||||
@@ -7,11 +7,11 @@ endif()
|
|||||||
set(SOURCES
|
set(SOURCES
|
||||||
core/mainwindow.cpp
|
core/mainwindow.cpp
|
||||||
core/application.cpp
|
core/application.cpp
|
||||||
core/appearance.cpp
|
|
||||||
core/player.cpp
|
core/player.cpp
|
||||||
core/commandlineoptions.cpp
|
core/commandlineoptions.cpp
|
||||||
core/database.cpp
|
core/database.cpp
|
||||||
core/sqlquery.cpp
|
core/sqlquery.cpp
|
||||||
|
core/sqlrow.cpp
|
||||||
core/metatypes.cpp
|
core/metatypes.cpp
|
||||||
core/deletefiles.cpp
|
core/deletefiles.cpp
|
||||||
core/filesystemmusicstorage.cpp
|
core/filesystemmusicstorage.cpp
|
||||||
@@ -34,14 +34,28 @@ set(SOURCES
|
|||||||
core/taskmanager.cpp
|
core/taskmanager.cpp
|
||||||
core/thread.cpp
|
core/thread.cpp
|
||||||
core/urlhandler.cpp
|
core/urlhandler.cpp
|
||||||
core/utilities.cpp
|
|
||||||
core/imageutils.cpp
|
|
||||||
core/iconloader.cpp
|
core/iconloader.cpp
|
||||||
core/standarditemiconloader.cpp
|
core/standarditemiconloader.cpp
|
||||||
core/scopedtransaction.cpp
|
core/scopedtransaction.cpp
|
||||||
core/translations.cpp
|
core/translations.cpp
|
||||||
core/systemtrayicon.cpp
|
core/systemtrayicon.cpp
|
||||||
|
|
||||||
|
utilities/strutils.cpp
|
||||||
|
utilities/envutils.cpp
|
||||||
|
utilities/colorutils.cpp
|
||||||
|
utilities/cryptutils.cpp
|
||||||
|
utilities/fileutils.cpp
|
||||||
|
utilities/diskutils.cpp
|
||||||
|
utilities/imageutils.cpp
|
||||||
|
utilities/macaddrutils.cpp
|
||||||
|
utilities/mimeutils.cpp
|
||||||
|
utilities/randutils.cpp
|
||||||
|
utilities/threadutils.cpp
|
||||||
|
utilities/timeutils.cpp
|
||||||
|
utilities/transliterate.cpp
|
||||||
|
utilities/xmlutils.cpp
|
||||||
|
utilities/filemanagerutils.cpp
|
||||||
|
|
||||||
engine/enginetype.cpp
|
engine/enginetype.cpp
|
||||||
engine/enginebase.cpp
|
engine/enginebase.cpp
|
||||||
engine/devicefinders.cpp
|
engine/devicefinders.cpp
|
||||||
@@ -59,8 +73,6 @@ set(SOURCES
|
|||||||
|
|
||||||
context/contextview.cpp
|
context/contextview.cpp
|
||||||
context/contextalbum.cpp
|
context/contextalbum.cpp
|
||||||
context/contextalbumsmodel.cpp
|
|
||||||
context/contextalbumsview.cpp
|
|
||||||
|
|
||||||
collection/collection.cpp
|
collection/collection.cpp
|
||||||
collection/collectionmodel.cpp
|
collection/collectionmodel.cpp
|
||||||
@@ -70,10 +82,11 @@ set(SOURCES
|
|||||||
collection/collectionitemdelegate.cpp
|
collection/collectionitemdelegate.cpp
|
||||||
collection/collectionviewcontainer.cpp
|
collection/collectionviewcontainer.cpp
|
||||||
collection/collectiondirectorymodel.cpp
|
collection/collectiondirectorymodel.cpp
|
||||||
|
collection/collectionfilteroptions.cpp
|
||||||
collection/collectionfilterwidget.cpp
|
collection/collectionfilterwidget.cpp
|
||||||
collection/collectionplaylistitem.cpp
|
collection/collectionplaylistitem.cpp
|
||||||
collection/collectionquery.cpp
|
collection/collectionquery.cpp
|
||||||
collection/sqlrow.cpp
|
collection/collectionqueryoptions.cpp
|
||||||
collection/savedgroupingmanager.cpp
|
collection/savedgroupingmanager.cpp
|
||||||
collection/groupbydialog.cpp
|
collection/groupbydialog.cpp
|
||||||
collection/collectiontask.cpp
|
collection/collectiontask.cpp
|
||||||
@@ -164,6 +177,8 @@ set(SOURCES
|
|||||||
lyrics/musixmatchlyricsprovider.cpp
|
lyrics/musixmatchlyricsprovider.cpp
|
||||||
lyrics/chartlyricsprovider.cpp
|
lyrics/chartlyricsprovider.cpp
|
||||||
|
|
||||||
|
providers/musixmatchprovider.cpp
|
||||||
|
|
||||||
settings/settingsdialog.cpp
|
settings/settingsdialog.cpp
|
||||||
settings/settingspage.cpp
|
settings/settingspage.cpp
|
||||||
settings/behavioursettingspage.cpp
|
settings/behavioursettingspage.cpp
|
||||||
@@ -188,6 +203,7 @@ set(SOURCES
|
|||||||
dialogs/deleteconfirmationdialog.cpp
|
dialogs/deleteconfirmationdialog.cpp
|
||||||
dialogs/lastfmimportdialog.cpp
|
dialogs/lastfmimportdialog.cpp
|
||||||
dialogs/snapdialog.cpp
|
dialogs/snapdialog.cpp
|
||||||
|
dialogs/saveplaylistsdialog.cpp
|
||||||
|
|
||||||
widgets/autoexpandingtreeview.cpp
|
widgets/autoexpandingtreeview.cpp
|
||||||
widgets/busyindicator.cpp
|
widgets/busyindicator.cpp
|
||||||
@@ -204,6 +220,8 @@ set(SOURCES
|
|||||||
widgets/multiloadingindicator.cpp
|
widgets/multiloadingindicator.cpp
|
||||||
widgets/playingwidget.cpp
|
widgets/playingwidget.cpp
|
||||||
widgets/renametablineedit.cpp
|
widgets/renametablineedit.cpp
|
||||||
|
widgets/sliderslider.cpp
|
||||||
|
widgets/prettyslider.cpp
|
||||||
widgets/volumeslider.cpp
|
widgets/volumeslider.cpp
|
||||||
widgets/stickyslider.cpp
|
widgets/stickyslider.cpp
|
||||||
widgets/stretchheaderview.cpp
|
widgets/stretchheaderview.cpp
|
||||||
@@ -212,6 +230,7 @@ set(SOURCES
|
|||||||
widgets/tracksliderslider.cpp
|
widgets/tracksliderslider.cpp
|
||||||
widgets/loginstatewidget.cpp
|
widgets/loginstatewidget.cpp
|
||||||
widgets/ratingwidget.cpp
|
widgets/ratingwidget.cpp
|
||||||
|
widgets/resizabletextedit.cpp
|
||||||
|
|
||||||
osd/osdbase.cpp
|
osd/osdbase.cpp
|
||||||
osd/osdpretty.cpp
|
osd/osdpretty.cpp
|
||||||
@@ -262,7 +281,6 @@ set(SOURCES
|
|||||||
set(HEADERS
|
set(HEADERS
|
||||||
core/mainwindow.h
|
core/mainwindow.h
|
||||||
core/application.h
|
core/application.h
|
||||||
core/appearance.h
|
|
||||||
core/player.h
|
core/player.h
|
||||||
core/database.h
|
core/database.h
|
||||||
core/deletefiles.h
|
core/deletefiles.h
|
||||||
@@ -298,8 +316,6 @@ set(HEADERS
|
|||||||
|
|
||||||
context/contextview.h
|
context/contextview.h
|
||||||
context/contextalbum.h
|
context/contextalbum.h
|
||||||
context/contextalbumsmodel.h
|
|
||||||
context/contextalbumsview.h
|
|
||||||
|
|
||||||
collection/collection.h
|
collection/collection.h
|
||||||
collection/collectionmodel.h
|
collection/collectionmodel.h
|
||||||
@@ -420,6 +436,7 @@ set(HEADERS
|
|||||||
dialogs/deleteconfirmationdialog.h
|
dialogs/deleteconfirmationdialog.h
|
||||||
dialogs/lastfmimportdialog.h
|
dialogs/lastfmimportdialog.h
|
||||||
dialogs/snapdialog.h
|
dialogs/snapdialog.h
|
||||||
|
dialogs/saveplaylistsdialog.h
|
||||||
|
|
||||||
widgets/autoexpandingtreeview.h
|
widgets/autoexpandingtreeview.h
|
||||||
widgets/busyindicator.h
|
widgets/busyindicator.h
|
||||||
@@ -435,6 +452,8 @@ set(HEADERS
|
|||||||
widgets/multiloadingindicator.h
|
widgets/multiloadingindicator.h
|
||||||
widgets/playingwidget.h
|
widgets/playingwidget.h
|
||||||
widgets/renametablineedit.h
|
widgets/renametablineedit.h
|
||||||
|
widgets/sliderslider.h
|
||||||
|
widgets/prettyslider.h
|
||||||
widgets/volumeslider.h
|
widgets/volumeslider.h
|
||||||
widgets/stickyslider.h
|
widgets/stickyslider.h
|
||||||
widgets/stretchheaderview.h
|
widgets/stretchheaderview.h
|
||||||
@@ -544,6 +563,7 @@ set(UI
|
|||||||
dialogs/userpassdialog.ui
|
dialogs/userpassdialog.ui
|
||||||
dialogs/lastfmimportdialog.ui
|
dialogs/lastfmimportdialog.ui
|
||||||
dialogs/snapdialog.ui
|
dialogs/snapdialog.ui
|
||||||
|
dialogs/saveplaylistsdialog.ui
|
||||||
|
|
||||||
widgets/trackslider.ui
|
widgets/trackslider.ui
|
||||||
widgets/fileview.ui
|
widgets/fileview.ui
|
||||||
@@ -569,7 +589,7 @@ option(USE_INSTALL_PREFIX "Look for data in CMAKE_INSTALL_PREFIX" ON)
|
|||||||
|
|
||||||
if(NOT APPLE)
|
if(NOT APPLE)
|
||||||
set(NOT_APPLE ON)
|
set(NOT_APPLE ON)
|
||||||
optional_source(NOT_APPLE SOURCES widgets/qsearchfield_nonmac.cpp core/qtsystemtrayicon.cpp HEADERS core/qtsystemtrayicon.h)
|
optional_source(NOT_APPLE SOURCES widgets/qsearchfield_qt.cpp core/qtsystemtrayicon.cpp HEADERS core/qtsystemtrayicon.h)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_GLOBALSHORTCUTS)
|
if(HAVE_GLOBALSHORTCUTS)
|
||||||
@@ -609,43 +629,42 @@ optional_source(HAVE_VLC SOURCES engine/vlcengine.cpp HEADERS engine/vlcengine.h
|
|||||||
|
|
||||||
# DBUS and MPRIS - Unix specific
|
# DBUS and MPRIS - Unix specific
|
||||||
if(UNIX AND HAVE_DBUS)
|
if(UNIX AND HAVE_DBUS)
|
||||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dbus)
|
|
||||||
|
|
||||||
optional_source(HAVE_DBUS SOURCES core/mpris2.cpp HEADERS core/mpris2.h)
|
optional_source(HAVE_DBUS SOURCES core/mpris2.cpp HEADERS core/mpris2.h)
|
||||||
optional_source(HAVE_UDISKS2 SOURCES device/udisks2lister.cpp HEADERS device/udisks2lister.h)
|
optional_source(HAVE_UDISKS2 SOURCES device/udisks2lister.cpp HEADERS device/udisks2lister.h)
|
||||||
|
|
||||||
# MPRIS 2.0 DBUS interfaces
|
# MPRIS 2.0 DBUS interfaces
|
||||||
qt_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.Player.xml core/mpris2.h mpris::Mpris2 core/mpris2_player Mpris2Player)
|
qt_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.Player.xml core/mpris2.h mpris::Mpris2 mpris2_player Mpris2Player)
|
||||||
qt_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.xml core/mpris2.h mpris::Mpris2 core/mpris2_root Mpris2Root)
|
qt_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.xml core/mpris2.h mpris::Mpris2 mpris2_root Mpris2Root)
|
||||||
qt_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.TrackList.xml core/mpris2.h mpris::Mpris2 core/mpris2_tracklist Mpris2TrackList)
|
qt_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.TrackList.xml core/mpris2.h mpris::Mpris2 mpris2_tracklist Mpris2TrackList)
|
||||||
|
|
||||||
# MPRIS 2.1 DBUS interfaces
|
# MPRIS 2.1 DBUS interfaces
|
||||||
qt_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.Playlists.xml core/mpris2.h mpris::Mpris2 core/mpris2_playlists Mpris2Playlists)
|
qt_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.Playlists.xml core/mpris2.h mpris::Mpris2 mpris2_playlists Mpris2Playlists)
|
||||||
|
|
||||||
# org.freedesktop.Notifications DBUS interface
|
# org.freedesktop.Notifications DBUS interface
|
||||||
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.Notifications.xml dbus/notification)
|
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.Notifications.xml notification)
|
||||||
|
|
||||||
# org.gnome.SettingsDaemon interface
|
# org.gnome.SettingsDaemon interface
|
||||||
qt_add_dbus_interface(SOURCES dbus/org.gnome.SettingsDaemon.MediaKeys.xml dbus/gnomesettingsdaemon)
|
qt_add_dbus_interface(SOURCES dbus/org.gnome.SettingsDaemon.MediaKeys.xml gnomesettingsdaemon)
|
||||||
|
|
||||||
# org.mate.SettingsDaemon interface
|
# org.mate.SettingsDaemon interface
|
||||||
qt_add_dbus_interface(SOURCES dbus/org.mate.SettingsDaemon.MediaKeys.xml dbus/matesettingsdaemon)
|
qt_add_dbus_interface(SOURCES dbus/org.mate.SettingsDaemon.MediaKeys.xml matesettingsdaemon)
|
||||||
|
|
||||||
# org.kde.KGlobalAccel interface
|
# org.kde.KGlobalAccel interface
|
||||||
qt_add_dbus_interface(SOURCES dbus/org.kde.KGlobalAccel.xml dbus/kglobalaccel)
|
qt_add_dbus_interface(SOURCES dbus/org.kde.KGlobalAccel.xml kglobalaccel)
|
||||||
qt_add_dbus_interface(SOURCES dbus/org.kde.KGlobalAccel.Component.xml dbus/kglobalaccelcomponent)
|
qt_add_dbus_interface(SOURCES dbus/org.kde.KGlobalAccel.Component.xml kglobalaccelcomponent)
|
||||||
|
|
||||||
if(HAVE_UDISKS2)
|
if(HAVE_UDISKS2)
|
||||||
set_source_files_properties(dbus/org.freedesktop.DBus.ObjectManager.xml PROPERTIES NO_NAMESPACE dbus/objectmanager INCLUDE dbus/metatypes.h)
|
set_source_files_properties(dbus/org.freedesktop.DBus.ObjectManager.xml PROPERTIES NO_NAMESPACE objectmanager INCLUDE dbus/metatypes.h)
|
||||||
set_source_files_properties(dbus/org.freedesktop.UDisks2.Filesystem.xml PROPERTIES NO_NAMESPACE dbus/udisks2filesystem INCLUDE dbus/metatypes.h)
|
set_source_files_properties(dbus/org.freedesktop.UDisks2.Filesystem.xml PROPERTIES NO_NAMESPACE udisks2filesystem INCLUDE dbus/metatypes.h)
|
||||||
set_source_files_properties(dbus/org.freedesktop.UDisks2.Block.xml PROPERTIES NO_NAMESPACE dbus/udisks2block INCLUDE dbus/metatypes.h)
|
set_source_files_properties(dbus/org.freedesktop.UDisks2.Block.xml PROPERTIES NO_NAMESPACE udisks2block INCLUDE dbus/metatypes.h)
|
||||||
set_source_files_properties(dbus/org.freedesktop.UDisks2.Drive.xml PROPERTIES NO_NAMESPACE dbus/udisks2drive INCLUDE dbus/metatypes.h)
|
set_source_files_properties(dbus/org.freedesktop.UDisks2.Drive.xml PROPERTIES NO_NAMESPACE udisks2drive INCLUDE dbus/metatypes.h)
|
||||||
set_source_files_properties(dbus/org.freedesktop.UDisks2.Job.xml PROPERTIES NO_NAMESPACE dbus/udisks2job INCLUDE dbus/metatypes.h)
|
set_source_files_properties(dbus/org.freedesktop.UDisks2.Job.xml PROPERTIES NO_NAMESPACE udisks2job INCLUDE dbus/metatypes.h)
|
||||||
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.DBus.ObjectManager.xml dbus/objectmanager)
|
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.DBus.ObjectManager.xml objectmanager)
|
||||||
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Filesystem.xml dbus/udisks2filesystem)
|
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Filesystem.xml udisks2filesystem)
|
||||||
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Block.xml dbus/udisks2block)
|
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Block.xml udisks2block)
|
||||||
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Drive.xml dbus/udisks2drive)
|
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Drive.xml udisks2drive)
|
||||||
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Job.xml dbus/udisks2job)
|
qt_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Job.xml udisks2job)
|
||||||
endif(HAVE_UDISKS2)
|
endif(HAVE_UDISKS2)
|
||||||
|
|
||||||
endif(UNIX AND HAVE_DBUS)
|
endif(UNIX AND HAVE_DBUS)
|
||||||
@@ -781,8 +800,8 @@ optional_source(HAVE_AUDIOCD
|
|||||||
# Platform specific - macOS
|
# Platform specific - macOS
|
||||||
optional_source(APPLE
|
optional_source(APPLE
|
||||||
SOURCES
|
SOURCES
|
||||||
|
utilities/macosutils.mm
|
||||||
core/scoped_nsautorelease_pool.mm
|
core/scoped_nsautorelease_pool.mm
|
||||||
core/mac_utilities.mm
|
|
||||||
core/mac_startup.mm
|
core/mac_startup.mm
|
||||||
core/macsystemtrayicon.mm
|
core/macsystemtrayicon.mm
|
||||||
core/macfslistener.mm
|
core/macfslistener.mm
|
||||||
@@ -803,8 +822,10 @@ optional_source(APPLE
|
|||||||
# Platform specific - Windows
|
# Platform specific - Windows
|
||||||
optional_source(WIN32
|
optional_source(WIN32
|
||||||
SOURCES
|
SOURCES
|
||||||
|
utilities/winutils.cpp
|
||||||
engine/directsounddevicefinder.cpp
|
engine/directsounddevicefinder.cpp
|
||||||
engine/mmdevicefinder.cpp
|
engine/mmdevicefinder.cpp
|
||||||
|
core/scopedwchararray.cpp
|
||||||
core/windows7thumbbar.cpp
|
core/windows7thumbbar.cpp
|
||||||
HEADERS
|
HEADERS
|
||||||
core/windows7thumbbar.h
|
core/windows7thumbbar.h
|
||||||
@@ -943,9 +964,14 @@ link_directories(
|
|||||||
${SQLITE_LIBRARY_DIRS}
|
${SQLITE_LIBRARY_DIRS}
|
||||||
${SINGLEAPPLICATION_LIBRARY_DIRS}
|
${SINGLEAPPLICATION_LIBRARY_DIRS}
|
||||||
${SINGLECOREAPPLICATION_LIBRARY_DIRS}
|
${SINGLECOREAPPLICATION_LIBRARY_DIRS}
|
||||||
${Iconv_LIBRARY_DIRS}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(HAVE_ICU)
|
||||||
|
link_directories(${ICU_LIBRARY_DIRS})
|
||||||
|
else()
|
||||||
|
link_directories(${Iconv_LIBRARY_DIRS})
|
||||||
|
endif()
|
||||||
|
|
||||||
if(HAVE_ALSA)
|
if(HAVE_ALSA)
|
||||||
link_directories(${ALSA_LIBRARY_DIRS})
|
link_directories(${ALSA_LIBRARY_DIRS})
|
||||||
endif()
|
endif()
|
||||||
@@ -1057,11 +1083,21 @@ target_link_libraries(strawberry_lib PUBLIC
|
|||||||
${QT_LIBRARIES}
|
${QT_LIBRARIES}
|
||||||
${SINGLEAPPLICATION_LIBRARIES}
|
${SINGLEAPPLICATION_LIBRARIES}
|
||||||
${SINGLECOREAPPLICATION_LIBRARIES}
|
${SINGLECOREAPPLICATION_LIBRARIES}
|
||||||
${Iconv_LIBRARIES}
|
|
||||||
libstrawberry-common
|
libstrawberry-common
|
||||||
libstrawberry-tagreader
|
libstrawberry-tagreader
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(HAVE_ICU)
|
||||||
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${ICU_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(strawberry_lib PRIVATE ${ICU_LIBRARIES})
|
||||||
|
else()
|
||||||
|
if(FREEBSD AND NOT Iconv_LIBRARIES)
|
||||||
|
set(Iconv_LIBRARIES iconv)
|
||||||
|
endif()
|
||||||
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${Iconv_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(strawberry_lib PRIVATE ${Iconv_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
if(HAVE_ALSA)
|
if(HAVE_ALSA)
|
||||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${ALSA_INCLUDE_DIRS})
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${ALSA_INCLUDE_DIRS})
|
||||||
target_link_libraries(strawberry_lib PRIVATE ${ALSA_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${ALSA_LIBRARIES})
|
||||||
@@ -1140,10 +1176,6 @@ if(HAVE_LIBMTP)
|
|||||||
target_link_libraries(strawberry_lib PRIVATE ${LIBMTP_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${LIBMTP_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(FREEBSD)
|
|
||||||
target_link_libraries(strawberry_lib PRIVATE iconv)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
target_link_libraries(strawberry_lib PRIVATE
|
target_link_libraries(strawberry_lib PRIVATE
|
||||||
"-framework AppKit"
|
"-framework AppKit"
|
||||||
|
|||||||
@@ -57,7 +57,11 @@ Analyzer::Base::Base(QWidget *parent, const uint scopeSize)
|
|||||||
lastscope_(512),
|
lastscope_(512),
|
||||||
new_frame_(false),
|
new_frame_(false),
|
||||||
is_playing_(false),
|
is_playing_(false),
|
||||||
timeout_(40) {}
|
timeout_(40) {
|
||||||
|
|
||||||
|
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Analyzer::Base::~Base() {
|
Analyzer::Base::~Base() {
|
||||||
delete fht_;
|
delete fht_;
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class QTimerEvent;
|
|||||||
|
|
||||||
namespace Analyzer {
|
namespace Analyzer {
|
||||||
|
|
||||||
typedef std::vector<float> Scope;
|
using Scope = std::vector<float>;
|
||||||
|
|
||||||
class Base : public QWidget {
|
class Base : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|||||||
@@ -33,7 +33,6 @@
|
|||||||
#include <QActionGroup>
|
#include <QActionGroup>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QtEvents>
|
#include <QtEvents>
|
||||||
#include <QtDebug>
|
|
||||||
|
|
||||||
#include "analyzercontainer.h"
|
#include "analyzercontainer.h"
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
#include <QtDebug>
|
|
||||||
|
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "core/taskmanager.h"
|
#include "core/taskmanager.h"
|
||||||
@@ -35,9 +34,9 @@
|
|||||||
#include "core/player.h"
|
#include "core/player.h"
|
||||||
#include "core/tagreaderclient.h"
|
#include "core/tagreaderclient.h"
|
||||||
#include "core/thread.h"
|
#include "core/thread.h"
|
||||||
#include "core/utilities.h"
|
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
|
#include "utilities/threadutils.h"
|
||||||
#include "collection.h"
|
#include "collection.h"
|
||||||
#include "collectionwatcher.h"
|
#include "collectionwatcher.h"
|
||||||
#include "collectionbackend.h"
|
#include "collectionbackend.h"
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
#include "core/utilities.h"
|
#include "utilities/threadutils.h"
|
||||||
|
|
||||||
class Application;
|
class Application;
|
||||||
class Thread;
|
class Thread;
|
||||||
|
|||||||
@@ -47,11 +47,12 @@
|
|||||||
#include "core/database.h"
|
#include "core/database.h"
|
||||||
#include "core/scopedtransaction.h"
|
#include "core/scopedtransaction.h"
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
|
#include "core/sqlrow.h"
|
||||||
#include "smartplaylists/smartplaylistsearch.h"
|
#include "smartplaylists/smartplaylistsearch.h"
|
||||||
|
|
||||||
#include "directory.h"
|
#include "collectiondirectory.h"
|
||||||
#include "sqlrow.h"
|
|
||||||
#include "collectionbackend.h"
|
#include "collectionbackend.h"
|
||||||
|
#include "collectionfilteroptions.h"
|
||||||
#include "collectionquery.h"
|
#include "collectionquery.h"
|
||||||
#include "collectiontask.h"
|
#include "collectiontask.h"
|
||||||
|
|
||||||
@@ -145,12 +146,12 @@ void CollectionBackend::ResetStatisticsAsync(const int id) {
|
|||||||
|
|
||||||
void CollectionBackend::LoadDirectories() {
|
void CollectionBackend::LoadDirectories() {
|
||||||
|
|
||||||
DirectoryList dirs = GetAllDirectories();
|
CollectionDirectoryList dirs = GetAllDirectories();
|
||||||
|
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
QSqlDatabase db(db_->Connect());
|
QSqlDatabase db(db_->Connect());
|
||||||
|
|
||||||
for (const Directory &dir : dirs) {
|
for (const CollectionDirectory &dir : dirs) {
|
||||||
emit DirectoryDiscovered(dir, SubdirsInDirectory(dir.id, db));
|
emit DirectoryDiscovered(dir, SubdirsInDirectory(dir.id, db));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,12 +208,12 @@ void CollectionBackend::ChangeDirPath(const int id, const QString &old_path, con
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectoryList CollectionBackend::GetAllDirectories() {
|
CollectionDirectoryList CollectionBackend::GetAllDirectories() {
|
||||||
|
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
QSqlDatabase db(db_->Connect());
|
QSqlDatabase db(db_->Connect());
|
||||||
|
|
||||||
DirectoryList ret;
|
CollectionDirectoryList ret;
|
||||||
|
|
||||||
SqlQuery q(db);
|
SqlQuery q(db);
|
||||||
q.prepare(QString("SELECT ROWID, path FROM %1").arg(dirs_table_));
|
q.prepare(QString("SELECT ROWID, path FROM %1").arg(dirs_table_));
|
||||||
@@ -222,7 +223,7 @@ DirectoryList CollectionBackend::GetAllDirectories() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (q.next()) {
|
while (q.next()) {
|
||||||
Directory dir;
|
CollectionDirectory dir;
|
||||||
dir.id = q.value(0).toInt();
|
dir.id = q.value(0).toInt();
|
||||||
dir.path = q.value(1).toString();
|
dir.path = q.value(1).toString();
|
||||||
|
|
||||||
@@ -232,7 +233,7 @@ DirectoryList CollectionBackend::GetAllDirectories() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SubdirectoryList CollectionBackend::SubdirsInDirectory(const int id) {
|
CollectionSubdirectoryList CollectionBackend::SubdirsInDirectory(const int id) {
|
||||||
|
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
QSqlDatabase db = db_->Connect();
|
QSqlDatabase db = db_->Connect();
|
||||||
@@ -240,19 +241,19 @@ SubdirectoryList CollectionBackend::SubdirsInDirectory(const int id) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SubdirectoryList CollectionBackend::SubdirsInDirectory(const int id, QSqlDatabase &db) {
|
CollectionSubdirectoryList CollectionBackend::SubdirsInDirectory(const int id, QSqlDatabase &db) {
|
||||||
|
|
||||||
SqlQuery q(db);
|
SqlQuery q(db);
|
||||||
q.prepare(QString("SELECT path, mtime FROM %1 WHERE directory_id = :dir").arg(subdirs_table_));
|
q.prepare(QString("SELECT path, mtime FROM %1 WHERE directory_id = :dir").arg(subdirs_table_));
|
||||||
q.BindValue(":dir", id);
|
q.BindValue(":dir", id);
|
||||||
if (!q.Exec()) {
|
if (!q.Exec()) {
|
||||||
db_->ReportErrors(q);
|
db_->ReportErrors(q);
|
||||||
return SubdirectoryList();
|
return CollectionSubdirectoryList();
|
||||||
}
|
}
|
||||||
|
|
||||||
SubdirectoryList subdirs;
|
CollectionSubdirectoryList subdirs;
|
||||||
while (q.next()) {
|
while (q.next()) {
|
||||||
Subdirectory subdir;
|
CollectionSubdirectory subdir;
|
||||||
subdir.directory_id = id;
|
subdir.directory_id = id;
|
||||||
subdir.path = q.value(0).toString();
|
subdir.path = q.value(0).toString();
|
||||||
subdir.mtime = q.value(1).toLongLong();
|
subdir.mtime = q.value(1).toLongLong();
|
||||||
@@ -339,15 +340,15 @@ void CollectionBackend::AddDirectory(const QString &path) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory dir;
|
CollectionDirectory dir;
|
||||||
dir.path = canonical_path;
|
dir.path = canonical_path;
|
||||||
dir.id = q.lastInsertId().toInt();
|
dir.id = q.lastInsertId().toInt();
|
||||||
|
|
||||||
emit DirectoryDiscovered(dir, SubdirectoryList());
|
emit DirectoryDiscovered(dir, CollectionSubdirectoryList());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionBackend::RemoveDirectory(const Directory &dir) {
|
void CollectionBackend::RemoveDirectory(const CollectionDirectory &dir) {
|
||||||
|
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
QSqlDatabase db(db_->Connect());
|
QSqlDatabase db(db_->Connect());
|
||||||
@@ -447,13 +448,13 @@ void CollectionBackend::SongPathChanged(const Song &song, const QFileInfo &new_f
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionBackend::AddOrUpdateSubdirs(const SubdirectoryList &subdirs) {
|
void CollectionBackend::AddOrUpdateSubdirs(const CollectionSubdirectoryList &subdirs) {
|
||||||
|
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
QSqlDatabase db(db_->Connect());
|
QSqlDatabase db(db_->Connect());
|
||||||
|
|
||||||
ScopedTransaction transaction(&db);
|
ScopedTransaction transaction(&db);
|
||||||
for (const Subdirectory &subdir : subdirs) {
|
for (const CollectionSubdirectory &subdir : subdirs) {
|
||||||
if (subdir.mtime == 0) {
|
if (subdir.mtime == 0) {
|
||||||
// Delete the subdirectory
|
// Delete the subdirectory
|
||||||
SqlQuery q(db);
|
SqlQuery q(db);
|
||||||
@@ -900,12 +901,12 @@ void CollectionBackend::MarkSongsUnavailable(const SongList &songs, const bool u
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList CollectionBackend::GetAll(const QString &column, const QueryOptions &opt) {
|
QStringList CollectionBackend::GetAll(const QString &column, const CollectionFilterOptions &filter_options) {
|
||||||
|
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
QSqlDatabase db(db_->Connect());
|
QSqlDatabase db(db_->Connect());
|
||||||
|
|
||||||
CollectionQuery query(db, songs_table_, fts_table_, opt);
|
CollectionQuery query(db, songs_table_, fts_table_, filter_options);
|
||||||
query.SetColumnSpec("DISTINCT " + column);
|
query.SetColumnSpec("DISTINCT " + column);
|
||||||
query.AddCompilationRequirement(false);
|
query.AddCompilationRequirement(false);
|
||||||
|
|
||||||
@@ -922,12 +923,12 @@ QStringList CollectionBackend::GetAll(const QString &column, const QueryOptions
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList CollectionBackend::GetAllArtists(const QueryOptions &opt) {
|
QStringList CollectionBackend::GetAllArtists(const CollectionFilterOptions &opt) {
|
||||||
|
|
||||||
return GetAll("artist", opt);
|
return GetAll("artist", opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList CollectionBackend::GetAllArtistsWithAlbums(const QueryOptions &opt) {
|
QStringList CollectionBackend::GetAllArtistsWithAlbums(const CollectionFilterOptions &opt) {
|
||||||
|
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
QSqlDatabase db(db_->Connect());
|
QSqlDatabase db(db_->Connect());
|
||||||
@@ -967,15 +968,15 @@ QStringList CollectionBackend::GetAllArtistsWithAlbums(const QueryOptions &opt)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectionBackend::AlbumList CollectionBackend::GetAllAlbums(const QueryOptions &opt) {
|
CollectionBackend::AlbumList CollectionBackend::GetAllAlbums(const CollectionFilterOptions &opt) {
|
||||||
return GetAlbums(QString(), false, opt);
|
return GetAlbums(QString(), false, opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectionBackend::AlbumList CollectionBackend::GetAlbumsByArtist(const QString &artist, const QueryOptions &opt) {
|
CollectionBackend::AlbumList CollectionBackend::GetAlbumsByArtist(const QString &artist, const CollectionFilterOptions &opt) {
|
||||||
return GetAlbums(artist, false, opt);
|
return GetAlbums(artist, false, opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
SongList CollectionBackend::GetArtistSongs(const QString &effective_albumartist, const QueryOptions &opt) {
|
SongList CollectionBackend::GetArtistSongs(const QString &effective_albumartist, const CollectionFilterOptions &opt) {
|
||||||
|
|
||||||
QSqlDatabase db(db_->Connect());
|
QSqlDatabase db(db_->Connect());
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
@@ -993,7 +994,7 @@ SongList CollectionBackend::GetArtistSongs(const QString &effective_albumartist,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SongList CollectionBackend::GetAlbumSongs(const QString &effective_albumartist, const QString &album, const QueryOptions &opt) {
|
SongList CollectionBackend::GetAlbumSongs(const QString &effective_albumartist, const QString &album, const CollectionFilterOptions &opt) {
|
||||||
|
|
||||||
QSqlDatabase db(db_->Connect());
|
QSqlDatabase db(db_->Connect());
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
@@ -1012,7 +1013,7 @@ SongList CollectionBackend::GetAlbumSongs(const QString &effective_albumartist,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SongList CollectionBackend::GetSongsByAlbum(const QString &album, const QueryOptions &opt) {
|
SongList CollectionBackend::GetSongsByAlbum(const QString &album, const CollectionFilterOptions &opt) {
|
||||||
|
|
||||||
QSqlDatabase db(db_->Connect());
|
QSqlDatabase db(db_->Connect());
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
@@ -1285,11 +1286,11 @@ SongList CollectionBackend::GetSongsByFingerprint(const QString &fingerprint) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CollectionBackend::AlbumList CollectionBackend::GetCompilationAlbums(const QueryOptions &opt) {
|
CollectionBackend::AlbumList CollectionBackend::GetCompilationAlbums(const CollectionFilterOptions &opt) {
|
||||||
return GetAlbums(QString(), true, opt);
|
return GetAlbums(QString(), true, opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
SongList CollectionBackend::GetCompilationSongs(const QString &album, const QueryOptions &opt) {
|
SongList CollectionBackend::GetCompilationSongs(const QString &album, const CollectionFilterOptions &opt) {
|
||||||
|
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
QSqlDatabase db(db_->Connect());
|
QSqlDatabase db(db_->Connect());
|
||||||
@@ -1314,10 +1315,6 @@ SongList CollectionBackend::GetCompilationSongs(const QString &album, const Quer
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Song::Source CollectionBackend::Source() const {
|
|
||||||
return source_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CollectionBackend::CompilationsNeedUpdating() {
|
void CollectionBackend::CompilationsNeedUpdating() {
|
||||||
|
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
@@ -1430,7 +1427,7 @@ bool CollectionBackend::UpdateCompilations(const QSqlDatabase &db, SongList &del
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectionBackend::AlbumList CollectionBackend::GetAlbums(const QString &artist, const bool compilation_required, const QueryOptions &opt) {
|
CollectionBackend::AlbumList CollectionBackend::GetAlbums(const QString &artist, const bool compilation_required, const CollectionFilterOptions &opt) {
|
||||||
|
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
QSqlDatabase db(db_->Connect());
|
QSqlDatabase db(db_->Connect());
|
||||||
@@ -1479,7 +1476,7 @@ CollectionBackend::AlbumList CollectionBackend::GetAlbums(const QString &artist,
|
|||||||
info.art_manual = QUrl::fromLocalFile(art_manual);
|
info.art_manual = QUrl::fromLocalFile(art_manual);
|
||||||
}
|
}
|
||||||
|
|
||||||
info.filetype = Song::FileType(query.Value(6).toInt());
|
info.filetype = static_cast<Song::FileType>(query.Value(6).toInt());
|
||||||
QString filetype = Song::TextForFiletype(info.filetype);
|
QString filetype = Song::TextForFiletype(info.filetype);
|
||||||
info.cue_path = query.Value(7).toString();
|
info.cue_path = query.Value(7).toString();
|
||||||
|
|
||||||
@@ -1520,7 +1517,7 @@ CollectionBackend::Album CollectionBackend::GetAlbumArt(const QString &effective
|
|||||||
ret.album = album;
|
ret.album = album;
|
||||||
ret.album_artist = effective_albumartist;
|
ret.album_artist = effective_albumartist;
|
||||||
|
|
||||||
CollectionQuery query(db, songs_table_, fts_table_, QueryOptions());
|
CollectionQuery query(db, songs_table_, fts_table_);
|
||||||
query.SetColumnSpec("art_automatic, art_manual, url");
|
query.SetColumnSpec("art_automatic, art_manual, url");
|
||||||
if (!effective_albumartist.isEmpty()) {
|
if (!effective_albumartist.isEmpty()) {
|
||||||
query.AddWhere("effective_albumartist", effective_albumartist);
|
query.AddWhere("effective_albumartist", effective_albumartist);
|
||||||
|
|||||||
@@ -38,8 +38,9 @@
|
|||||||
|
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
#include "core/sqlquery.h"
|
#include "core/sqlquery.h"
|
||||||
|
#include "collectionfilteroptions.h"
|
||||||
#include "collectionquery.h"
|
#include "collectionquery.h"
|
||||||
#include "directory.h"
|
#include "collectiondirectory.h"
|
||||||
|
|
||||||
class QThread;
|
class QThread;
|
||||||
class TaskManager;
|
class TaskManager;
|
||||||
@@ -53,7 +54,7 @@ class CollectionBackendInterface : public QObject {
|
|||||||
explicit CollectionBackendInterface(QObject *parent = nullptr) : QObject(parent) {}
|
explicit CollectionBackendInterface(QObject *parent = nullptr) : QObject(parent) {}
|
||||||
|
|
||||||
struct Album {
|
struct Album {
|
||||||
Album() {}
|
Album() : filetype(Song::FileType_Unknown) {}
|
||||||
Album(const QString &_album_artist, const QString &_album, const QUrl &_art_automatic, const QUrl &_art_manual, const QList<QUrl> &_urls, const Song::FileType _filetype, const QString &_cue_path)
|
Album(const QString &_album_artist, const QString &_album, const QUrl &_art_automatic, const QUrl &_art_manual, const QList<QUrl> &_urls, const Song::FileType _filetype, const QString &_cue_path)
|
||||||
: album_artist(_album_artist),
|
: album_artist(_album_artist),
|
||||||
album(_album),
|
album(_album),
|
||||||
@@ -72,11 +73,13 @@ class CollectionBackendInterface : public QObject {
|
|||||||
Song::FileType filetype;
|
Song::FileType filetype;
|
||||||
QString cue_path;
|
QString cue_path;
|
||||||
};
|
};
|
||||||
typedef QList<Album> AlbumList;
|
using AlbumList = QList<Album>;
|
||||||
|
|
||||||
virtual QString songs_table() const = 0;
|
virtual QString songs_table() const = 0;
|
||||||
virtual QString fts_table() const = 0;
|
virtual QString fts_table() const = 0;
|
||||||
|
|
||||||
|
virtual Song::Source source() const = 0;
|
||||||
|
|
||||||
virtual Database *db() const = 0;
|
virtual Database *db() const = 0;
|
||||||
|
|
||||||
// Get a list of directories in the collection. Emits DirectoriesDiscovered.
|
// Get a list of directories in the collection. Emits DirectoriesDiscovered.
|
||||||
@@ -88,23 +91,23 @@ class CollectionBackendInterface : public QObject {
|
|||||||
|
|
||||||
virtual SongList FindSongsInDirectory(const int id) = 0;
|
virtual SongList FindSongsInDirectory(const int id) = 0;
|
||||||
virtual SongList SongsWithMissingFingerprint(const int id) = 0;
|
virtual SongList SongsWithMissingFingerprint(const int id) = 0;
|
||||||
virtual SubdirectoryList SubdirsInDirectory(const int id) = 0;
|
virtual CollectionSubdirectoryList SubdirsInDirectory(const int id) = 0;
|
||||||
virtual DirectoryList GetAllDirectories() = 0;
|
virtual CollectionDirectoryList GetAllDirectories() = 0;
|
||||||
virtual void ChangeDirPath(const int id, const QString &old_path, const QString &new_path) = 0;
|
virtual void ChangeDirPath(const int id, const QString &old_path, const QString &new_path) = 0;
|
||||||
|
|
||||||
virtual SongList GetAllSongs() = 0;
|
virtual SongList GetAllSongs() = 0;
|
||||||
|
|
||||||
virtual QStringList GetAllArtists(const QueryOptions &opt = QueryOptions()) = 0;
|
virtual QStringList GetAllArtists(const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
|
||||||
virtual QStringList GetAllArtistsWithAlbums(const QueryOptions &opt = QueryOptions()) = 0;
|
virtual QStringList GetAllArtistsWithAlbums(const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
|
||||||
virtual SongList GetArtistSongs(const QString &effective_albumartist, const QueryOptions &opt = QueryOptions()) = 0;
|
virtual SongList GetArtistSongs(const QString &effective_albumartist, const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
|
||||||
virtual SongList GetAlbumSongs(const QString &effective_albumartist, const QString &album, const QueryOptions &opt = QueryOptions()) = 0;
|
virtual SongList GetAlbumSongs(const QString &effective_albumartist, const QString &album, const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
|
||||||
virtual SongList GetSongsByAlbum(const QString &album, const QueryOptions &opt = QueryOptions()) = 0;
|
virtual SongList GetSongsByAlbum(const QString &album, const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
|
||||||
|
|
||||||
virtual SongList GetCompilationSongs(const QString &album, const QueryOptions &opt = QueryOptions()) = 0;
|
virtual SongList GetCompilationSongs(const QString &album, const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
|
||||||
|
|
||||||
virtual AlbumList GetAllAlbums(const QueryOptions &opt = QueryOptions()) = 0;
|
virtual AlbumList GetAllAlbums(const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
|
||||||
virtual AlbumList GetAlbumsByArtist(const QString &artist, const QueryOptions &opt = QueryOptions()) = 0;
|
virtual AlbumList GetAlbumsByArtist(const QString &artist, const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
|
||||||
virtual AlbumList GetCompilationAlbums(const QueryOptions &opt = QueryOptions()) = 0;
|
virtual AlbumList GetCompilationAlbums(const CollectionFilterOptions &opt = CollectionFilterOptions()) = 0;
|
||||||
|
|
||||||
virtual void UpdateManualAlbumArtAsync(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_automatic = false) = 0;
|
virtual void UpdateManualAlbumArtAsync(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_automatic = false) = 0;
|
||||||
virtual void UpdateAutomaticAlbumArtAsync(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_manual = false) = 0;
|
virtual void UpdateAutomaticAlbumArtAsync(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_manual = false) = 0;
|
||||||
@@ -122,7 +125,7 @@ class CollectionBackendInterface : public QObject {
|
|||||||
virtual Song GetSongByUrl(const QUrl &url, const qint64 beginning = 0) = 0;
|
virtual Song GetSongByUrl(const QUrl &url, const qint64 beginning = 0) = 0;
|
||||||
|
|
||||||
virtual void AddDirectory(const QString &path) = 0;
|
virtual void AddDirectory(const QString &path) = 0;
|
||||||
virtual void RemoveDirectory(const Directory &dir) = 0;
|
virtual void RemoveDirectory(const CollectionDirectory &dir) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CollectionBackend : public CollectionBackendInterface {
|
class CollectionBackend : public CollectionBackendInterface {
|
||||||
@@ -139,6 +142,8 @@ class CollectionBackend : public CollectionBackendInterface {
|
|||||||
|
|
||||||
void ReportErrors(const CollectionQuery &query);
|
void ReportErrors(const CollectionQuery &query);
|
||||||
|
|
||||||
|
Song::Source source() const override { return source_; }
|
||||||
|
|
||||||
Database *db() const override { return db_; }
|
Database *db() const override { return db_; }
|
||||||
|
|
||||||
QString songs_table() const override { return songs_table_; }
|
QString songs_table() const override { return songs_table_; }
|
||||||
@@ -155,24 +160,24 @@ class CollectionBackend : public CollectionBackendInterface {
|
|||||||
|
|
||||||
SongList FindSongsInDirectory(const int id) override;
|
SongList FindSongsInDirectory(const int id) override;
|
||||||
SongList SongsWithMissingFingerprint(const int id) override;
|
SongList SongsWithMissingFingerprint(const int id) override;
|
||||||
SubdirectoryList SubdirsInDirectory(const int id) override;
|
CollectionSubdirectoryList SubdirsInDirectory(const int id) override;
|
||||||
DirectoryList GetAllDirectories() override;
|
CollectionDirectoryList GetAllDirectories() override;
|
||||||
void ChangeDirPath(const int id, const QString &old_path, const QString &new_path) override;
|
void ChangeDirPath(const int id, const QString &old_path, const QString &new_path) override;
|
||||||
|
|
||||||
SongList GetAllSongs() override;
|
SongList GetAllSongs() override;
|
||||||
|
|
||||||
QStringList GetAll(const QString &column, const QueryOptions &opt = QueryOptions());
|
QStringList GetAll(const QString &column, const CollectionFilterOptions &filter_options = CollectionFilterOptions());
|
||||||
QStringList GetAllArtists(const QueryOptions &opt = QueryOptions()) override;
|
QStringList GetAllArtists(const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
|
||||||
QStringList GetAllArtistsWithAlbums(const QueryOptions &opt = QueryOptions()) override;
|
QStringList GetAllArtistsWithAlbums(const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
|
||||||
SongList GetArtistSongs(const QString &effective_albumartist, const QueryOptions &opt = QueryOptions()) override;
|
SongList GetArtistSongs(const QString &effective_albumartist, const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
|
||||||
SongList GetAlbumSongs(const QString &effective_albumartist, const QString &album, const QueryOptions &opt = QueryOptions()) override;
|
SongList GetAlbumSongs(const QString &effective_albumartist, const QString &album, const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
|
||||||
SongList GetSongsByAlbum(const QString &album, const QueryOptions &opt = QueryOptions()) override;
|
SongList GetSongsByAlbum(const QString &album, const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
|
||||||
|
|
||||||
SongList GetCompilationSongs(const QString &album, const QueryOptions &opt = QueryOptions()) override;
|
SongList GetCompilationSongs(const QString &album, const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
|
||||||
|
|
||||||
AlbumList GetAllAlbums(const QueryOptions &opt = QueryOptions()) override;
|
AlbumList GetAllAlbums(const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
|
||||||
AlbumList GetCompilationAlbums(const QueryOptions &opt = QueryOptions()) override;
|
AlbumList GetCompilationAlbums(const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
|
||||||
AlbumList GetAlbumsByArtist(const QString &artist, const QueryOptions &opt = QueryOptions()) override;
|
AlbumList GetAlbumsByArtist(const QString &artist, const CollectionFilterOptions &opt = CollectionFilterOptions()) override;
|
||||||
|
|
||||||
void UpdateManualAlbumArtAsync(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_automatic = false) override;
|
void UpdateManualAlbumArtAsync(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_automatic = false) override;
|
||||||
void UpdateAutomaticAlbumArtAsync(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_manual = false) override;
|
void UpdateAutomaticAlbumArtAsync(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_manual = false) override;
|
||||||
@@ -188,7 +193,7 @@ class CollectionBackend : public CollectionBackendInterface {
|
|||||||
Song GetSongByUrl(const QUrl &url, qint64 beginning = 0) override;
|
Song GetSongByUrl(const QUrl &url, qint64 beginning = 0) override;
|
||||||
|
|
||||||
void AddDirectory(const QString &path) override;
|
void AddDirectory(const QString &path) override;
|
||||||
void RemoveDirectory(const Directory &dir) override;
|
void RemoveDirectory(const CollectionDirectory &dir) override;
|
||||||
|
|
||||||
bool ExecCollectionQuery(CollectionQuery *query, SongList &songs);
|
bool ExecCollectionQuery(CollectionQuery *query, SongList &songs);
|
||||||
bool ExecCollectionQuery(CollectionQuery *query, SongMap &songs);
|
bool ExecCollectionQuery(CollectionQuery *query, SongMap &songs);
|
||||||
@@ -207,8 +212,6 @@ class CollectionBackend : public CollectionBackendInterface {
|
|||||||
SongList SmartPlaylistsGetAllSongs();
|
SongList SmartPlaylistsGetAllSongs();
|
||||||
SongList SmartPlaylistsFindSongs(const SmartPlaylistSearch &search);
|
SongList SmartPlaylistsFindSongs(const SmartPlaylistSearch &search);
|
||||||
|
|
||||||
Song::Source Source() const;
|
|
||||||
|
|
||||||
void AddOrUpdateSongsAsync(const SongList &songs);
|
void AddOrUpdateSongsAsync(const SongList &songs);
|
||||||
void UpdateSongsBySongIDAsync(const SongMap &new_songs);
|
void UpdateSongsBySongIDAsync(const SongMap &new_songs);
|
||||||
|
|
||||||
@@ -226,7 +229,7 @@ class CollectionBackend : public CollectionBackendInterface {
|
|||||||
void UpdateMTimesOnly(const SongList &songs);
|
void UpdateMTimesOnly(const SongList &songs);
|
||||||
void DeleteSongs(const SongList &songs);
|
void DeleteSongs(const SongList &songs);
|
||||||
void MarkSongsUnavailable(const SongList &songs, const bool unavailable = true);
|
void MarkSongsUnavailable(const SongList &songs, const bool unavailable = true);
|
||||||
void AddOrUpdateSubdirs(const SubdirectoryList &subdirs);
|
void AddOrUpdateSubdirs(const CollectionSubdirectoryList &subdirs);
|
||||||
void CompilationsNeedUpdating();
|
void CompilationsNeedUpdating();
|
||||||
void UpdateManualAlbumArt(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_automatic = false);
|
void UpdateManualAlbumArt(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_automatic = false);
|
||||||
void UpdateAutomaticAlbumArt(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_manual = false);
|
void UpdateAutomaticAlbumArt(const QString &effective_albumartist, const QString &album, const QUrl &cover_url, const bool clear_art_manual = false);
|
||||||
@@ -248,8 +251,8 @@ class CollectionBackend : public CollectionBackendInterface {
|
|||||||
void ExpireSongs(const int directory_id, const int expire_unavailable_songs_days);
|
void ExpireSongs(const int directory_id, const int expire_unavailable_songs_days);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void DirectoryDiscovered(Directory, SubdirectoryList);
|
void DirectoryDiscovered(CollectionDirectory, CollectionSubdirectoryList);
|
||||||
void DirectoryDeleted(Directory);
|
void DirectoryDeleted(CollectionDirectory);
|
||||||
|
|
||||||
void SongsDiscovered(SongList);
|
void SongsDiscovered(SongList);
|
||||||
void SongsDeleted(SongList);
|
void SongsDeleted(SongList);
|
||||||
@@ -278,9 +281,9 @@ class CollectionBackend : public CollectionBackendInterface {
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool UpdateCompilations(const QSqlDatabase &db, SongList &deleted_songs, SongList &added_songs, const QUrl &url, const bool compilation_detected);
|
bool UpdateCompilations(const QSqlDatabase &db, SongList &deleted_songs, SongList &added_songs, const QUrl &url, const bool compilation_detected);
|
||||||
AlbumList GetAlbums(const QString &artist, const QString &album_artist, const bool compilation_required = false, const QueryOptions &opt = QueryOptions());
|
AlbumList GetAlbums(const QString &artist, const QString &album_artist, const bool compilation_required = false, const CollectionFilterOptions &opt = CollectionFilterOptions());
|
||||||
AlbumList GetAlbums(const QString &artist, const bool compilation_required, const QueryOptions &opt = QueryOptions());
|
AlbumList GetAlbums(const QString &artist, const bool compilation_required, const CollectionFilterOptions &opt = CollectionFilterOptions());
|
||||||
SubdirectoryList SubdirsInDirectory(const int id, QSqlDatabase &db);
|
CollectionSubdirectoryList SubdirsInDirectory(const int id, QSqlDatabase &db);
|
||||||
|
|
||||||
Song GetSongById(const int id, QSqlDatabase &db);
|
Song GetSongById(const int id, QSqlDatabase &db);
|
||||||
SongList GetSongsById(const QStringList &ids, QSqlDatabase &db);
|
SongList GetSongsById(const QStringList &ids, QSqlDatabase &db);
|
||||||
|
|||||||
57
src/collection/collectiondirectory.h
Normal file
57
src/collection/collectiondirectory.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Strawberry Music Player
|
||||||
|
* This file was part of Clementine.
|
||||||
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
*
|
||||||
|
* Strawberry 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.
|
||||||
|
*
|
||||||
|
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COLLECTIONDIRECTORY_H
|
||||||
|
#define COLLECTIONDIRECTORY_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <QMetaType>
|
||||||
|
#include <QList>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
struct CollectionDirectory {
|
||||||
|
CollectionDirectory() : id(-1) {}
|
||||||
|
|
||||||
|
bool operator==(const CollectionDirectory &other) const {
|
||||||
|
return path == other.path && id == other.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString path;
|
||||||
|
int id;
|
||||||
|
};
|
||||||
|
Q_DECLARE_METATYPE(CollectionDirectory)
|
||||||
|
|
||||||
|
using CollectionDirectoryList = QList<CollectionDirectory>;
|
||||||
|
Q_DECLARE_METATYPE(CollectionDirectoryList)
|
||||||
|
|
||||||
|
struct CollectionSubdirectory {
|
||||||
|
CollectionSubdirectory() : directory_id(-1), mtime(0) {}
|
||||||
|
|
||||||
|
int directory_id;
|
||||||
|
QString path;
|
||||||
|
qint64 mtime;
|
||||||
|
};
|
||||||
|
Q_DECLARE_METATYPE(CollectionSubdirectory)
|
||||||
|
|
||||||
|
using CollectionSubdirectoryList = QList<CollectionSubdirectory>;
|
||||||
|
Q_DECLARE_METATYPE(CollectionSubdirectoryList)
|
||||||
|
|
||||||
|
#endif // COLLECTIONDIRECTORY_H
|
||||||
@@ -29,8 +29,8 @@
|
|||||||
#include "core/filesystemmusicstorage.h"
|
#include "core/filesystemmusicstorage.h"
|
||||||
#include "core/iconloader.h"
|
#include "core/iconloader.h"
|
||||||
#include "core/musicstorage.h"
|
#include "core/musicstorage.h"
|
||||||
#include "core/utilities.h"
|
#include "utilities/diskutils.h"
|
||||||
#include "directory.h"
|
#include "collectiondirectory.h"
|
||||||
#include "collectionbackend.h"
|
#include "collectionbackend.h"
|
||||||
#include "collectiondirectorymodel.h"
|
#include "collectiondirectorymodel.h"
|
||||||
|
|
||||||
@@ -46,17 +46,17 @@ CollectionDirectoryModel::CollectionDirectoryModel(CollectionBackend *backend, Q
|
|||||||
|
|
||||||
CollectionDirectoryModel::~CollectionDirectoryModel() = default;
|
CollectionDirectoryModel::~CollectionDirectoryModel() = default;
|
||||||
|
|
||||||
void CollectionDirectoryModel::DirectoryDiscovered(const Directory &dir) {
|
void CollectionDirectoryModel::DirectoryDiscovered(const CollectionDirectory &dir) {
|
||||||
|
|
||||||
QStandardItem *item = new QStandardItem(dir.path);
|
QStandardItem *item = new QStandardItem(dir.path);
|
||||||
item->setData(dir.id, kIdRole);
|
item->setData(dir.id, kIdRole);
|
||||||
item->setIcon(dir_icon_);
|
item->setIcon(dir_icon_);
|
||||||
storage_ << std::make_shared<FilesystemMusicStorage>(dir.path, dir.id);
|
storage_ << std::make_shared<FilesystemMusicStorage>(backend_->source(), dir.path, dir.id);
|
||||||
appendRow(item);
|
appendRow(item);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionDirectoryModel::DirectoryDeleted(const Directory &dir) {
|
void CollectionDirectoryModel::DirectoryDeleted(const CollectionDirectory &dir) {
|
||||||
|
|
||||||
for (int i = 0; i < rowCount(); ++i) {
|
for (int i = 0; i < rowCount(); ++i) {
|
||||||
if (item(i, 0)->data(kIdRole).toInt() == dir.id) {
|
if (item(i, 0)->data(kIdRole).toInt() == dir.id) {
|
||||||
@@ -80,7 +80,7 @@ void CollectionDirectoryModel::RemoveDirectory(const QModelIndex &idx) {
|
|||||||
|
|
||||||
if (!backend_ || !idx.isValid()) return;
|
if (!backend_ || !idx.isValid()) return;
|
||||||
|
|
||||||
Directory dir;
|
CollectionDirectory dir;
|
||||||
dir.path = idx.data().toString();
|
dir.path = idx.data().toString();
|
||||||
dir.id = idx.data(kIdRole).toInt();
|
dir.id = idx.data(kIdRole).toInt();
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
class QModelIndex;
|
class QModelIndex;
|
||||||
|
|
||||||
struct Directory;
|
struct CollectionDirectory;
|
||||||
class CollectionBackend;
|
class CollectionBackend;
|
||||||
class MusicStorage;
|
class MusicStorage;
|
||||||
|
|
||||||
@@ -53,8 +53,8 @@ class CollectionDirectoryModel : public QStandardItemModel {
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
// To be called by the backend
|
// To be called by the backend
|
||||||
void DirectoryDiscovered(const Directory &directories);
|
void DirectoryDiscovered(const CollectionDirectory &directories);
|
||||||
void DirectoryDeleted(const Directory &directories);
|
void DirectoryDeleted(const CollectionDirectory &directories);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int kIdRole = Qt::UserRole + 1;
|
static const int kIdRole = Qt::UserRole + 1;
|
||||||
|
|||||||
42
src/collection/collectionfilteroptions.cpp
Normal file
42
src/collection/collectionfilteroptions.cpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Strawberry Music Player
|
||||||
|
* Copyright 2023, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
|
*
|
||||||
|
* Strawberry 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.
|
||||||
|
*
|
||||||
|
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#include "core/song.h"
|
||||||
|
|
||||||
|
#include "collectionfilteroptions.h"
|
||||||
|
|
||||||
|
CollectionFilterOptions::CollectionFilterOptions() : filter_mode_(FilterMode_All), max_age_(-1) {}
|
||||||
|
|
||||||
|
bool CollectionFilterOptions::Matches(const Song &song) const {
|
||||||
|
|
||||||
|
if (max_age_ != -1) {
|
||||||
|
const qint64 cutoff = QDateTime::currentDateTime().toSecsSinceEpoch() - max_age_;
|
||||||
|
if (song.ctime() <= cutoff) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filter_text_.isNull()) {
|
||||||
|
return song.artist().contains(filter_text_, Qt::CaseInsensitive) || song.album().contains(filter_text_, Qt::CaseInsensitive) || song.title().contains(filter_text_, Qt::CaseInsensitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
65
src/collection/collectionfilteroptions.h
Normal file
65
src/collection/collectionfilteroptions.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Strawberry Music Player
|
||||||
|
* Copyright 2023, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
|
*
|
||||||
|
* Strawberry 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.
|
||||||
|
*
|
||||||
|
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COLLECTIONFILTEROPTIONS_H
|
||||||
|
#define COLLECTIONFILTEROPTIONS_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "core/song.h"
|
||||||
|
|
||||||
|
class CollectionFilterOptions {
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit CollectionFilterOptions();
|
||||||
|
|
||||||
|
// Filter mode:
|
||||||
|
// - use the all songs table
|
||||||
|
// - use the duplicated songs view; by duplicated we mean those songs for which the (artist, album, title) tuple is found more than once in the songs table
|
||||||
|
// - use the untagged songs view; by untagged we mean those for which at least one of the (artist, album, title) tags is empty
|
||||||
|
// Please note that additional filtering based on FTS table (the filter attribute) won't work in Duplicates and Untagged modes.
|
||||||
|
enum FilterMode {
|
||||||
|
FilterMode_All,
|
||||||
|
FilterMode_Duplicates,
|
||||||
|
FilterMode_Untagged
|
||||||
|
};
|
||||||
|
|
||||||
|
FilterMode filter_mode() const { return filter_mode_; }
|
||||||
|
int max_age() const { return max_age_; }
|
||||||
|
QString filter_text() const { return filter_text_; }
|
||||||
|
|
||||||
|
void set_filter_mode(const FilterMode filter_mode) {
|
||||||
|
filter_mode_ = filter_mode;
|
||||||
|
filter_text_.clear();
|
||||||
|
}
|
||||||
|
void set_max_age(const int max_age) { max_age_ = max_age; }
|
||||||
|
void set_filter_text(const QString &filter_text) {
|
||||||
|
filter_mode_ = FilterMode_All;
|
||||||
|
filter_text_ = filter_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Matches(const Song &song) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
FilterMode filter_mode_;
|
||||||
|
int max_age_;
|
||||||
|
QString filter_text_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COLLECTIONFILTEROPTIONS_H
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2019-2022, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -45,6 +46,7 @@
|
|||||||
#include "core/iconloader.h"
|
#include "core/iconloader.h"
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
|
#include "collectionfilteroptions.h"
|
||||||
#include "collectionmodel.h"
|
#include "collectionmodel.h"
|
||||||
#include "collectionquery.h"
|
#include "collectionquery.h"
|
||||||
#include "savedgroupingmanager.h"
|
#include "savedgroupingmanager.h"
|
||||||
@@ -58,7 +60,12 @@ CollectionFilterWidget::CollectionFilterWidget(QWidget *parent)
|
|||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
ui_(new Ui_CollectionFilterWidget),
|
ui_(new Ui_CollectionFilterWidget),
|
||||||
model_(nullptr),
|
model_(nullptr),
|
||||||
group_by_dialog_(new GroupByDialog),
|
group_by_dialog_(new GroupByDialog(this)),
|
||||||
|
groupings_manager_(nullptr),
|
||||||
|
filter_age_menu_(nullptr),
|
||||||
|
group_by_menu_(nullptr),
|
||||||
|
collection_menu_(nullptr),
|
||||||
|
group_by_group_(nullptr),
|
||||||
filter_delay_(new QTimer(this)),
|
filter_delay_(new QTimer(this)),
|
||||||
filter_applies_to_model_(true),
|
filter_applies_to_model_(true),
|
||||||
delay_behaviour_(DelayedOnLargeLibraries) {
|
delay_behaviour_(DelayedOnLargeLibraries) {
|
||||||
@@ -114,13 +121,8 @@ CollectionFilterWidget::CollectionFilterWidget(QWidget *parent)
|
|||||||
filter_ages_[ui_->filter_age_three_months] = 60 * 60 * 24 * 30 * 3;
|
filter_ages_[ui_->filter_age_three_months] = 60 * 60 * 24 * 30 * 3;
|
||||||
filter_ages_[ui_->filter_age_year] = 60 * 60 * 24 * 365;
|
filter_ages_[ui_->filter_age_year] = 60 * 60 * 24 * 365;
|
||||||
|
|
||||||
// "Group by ..."
|
|
||||||
group_by_group_ = CreateGroupByActions(this);
|
|
||||||
|
|
||||||
group_by_menu_ = new QMenu(tr("Group by"), this);
|
group_by_menu_ = new QMenu(tr("Group by"), this);
|
||||||
group_by_menu_->addActions(group_by_group_->actions());
|
|
||||||
|
|
||||||
QObject::connect(group_by_group_, &QActionGroup::triggered, this, &CollectionFilterWidget::GroupByClicked);
|
|
||||||
QObject::connect(ui_->save_grouping, &QAction::triggered, this, &CollectionFilterWidget::SaveGroupBy);
|
QObject::connect(ui_->save_grouping, &QAction::triggered, this, &CollectionFilterWidget::SaveGroupBy);
|
||||||
QObject::connect(ui_->manage_groupings, &QAction::triggered, this, &CollectionFilterWidget::ShowGroupingManager);
|
QObject::connect(ui_->manage_groupings, &QAction::triggered, this, &CollectionFilterWidget::ShowGroupingManager);
|
||||||
|
|
||||||
@@ -147,8 +149,8 @@ void CollectionFilterWidget::Init(CollectionModel *model) {
|
|||||||
|
|
||||||
if (model_) {
|
if (model_) {
|
||||||
QObject::disconnect(model_, nullptr, this, nullptr);
|
QObject::disconnect(model_, nullptr, this, nullptr);
|
||||||
QObject::disconnect(model_, nullptr, group_by_dialog_.get(), nullptr);
|
QObject::disconnect(model_, nullptr, group_by_dialog_, nullptr);
|
||||||
QObject::disconnect(group_by_dialog_.get(), nullptr, model_, nullptr);
|
QObject::disconnect(group_by_dialog_, nullptr, model_, nullptr);
|
||||||
QList<QAction*> filter_ages = filter_ages_.keys();
|
QList<QAction*> filter_ages = filter_ages_.keys();
|
||||||
for (QAction *action : filter_ages) {
|
for (QAction *action : filter_ages) {
|
||||||
QObject::disconnect(action, &QAction::triggered, model_, nullptr);
|
QObject::disconnect(action, &QAction::triggered, model_, nullptr);
|
||||||
@@ -158,9 +160,9 @@ void CollectionFilterWidget::Init(CollectionModel *model) {
|
|||||||
model_ = model;
|
model_ = model;
|
||||||
|
|
||||||
// Connect signals
|
// Connect signals
|
||||||
QObject::connect(model_, &CollectionModel::GroupingChanged, group_by_dialog_.get(), &GroupByDialog::CollectionGroupingChanged);
|
QObject::connect(model_, &CollectionModel::GroupingChanged, group_by_dialog_, &GroupByDialog::CollectionGroupingChanged);
|
||||||
QObject::connect(model_, &CollectionModel::GroupingChanged, this, &CollectionFilterWidget::GroupingChanged);
|
QObject::connect(model_, &CollectionModel::GroupingChanged, this, &CollectionFilterWidget::GroupingChanged);
|
||||||
QObject::connect(group_by_dialog_.get(), &GroupByDialog::Accepted, model_, &CollectionModel::SetGroupBy);
|
QObject::connect(group_by_dialog_, &GroupByDialog::Accepted, model_, &CollectionModel::SetGroupBy);
|
||||||
|
|
||||||
QList<QAction*> filter_ages = filter_ages_.keys();
|
QList<QAction*> filter_ages = filter_ages_.keys();
|
||||||
for (QAction *action : filter_ages) {
|
for (QAction *action : filter_ages) {
|
||||||
@@ -176,15 +178,31 @@ void CollectionFilterWidget::Init(CollectionModel *model) {
|
|||||||
if (s.contains(group_by_version())) version = s.value(group_by_version(), 0).toInt();
|
if (s.contains(group_by_version())) version = s.value(group_by_version(), 0).toInt();
|
||||||
if (version == 1) {
|
if (version == 1) {
|
||||||
model_->SetGroupBy(CollectionModel::Grouping(
|
model_->SetGroupBy(CollectionModel::Grouping(
|
||||||
CollectionModel::GroupBy(s.value(group_by(1), static_cast<int>(CollectionModel::GroupBy_AlbumArtist)).toInt()),
|
CollectionModel::GroupBy(s.value(group_by_key(1), static_cast<int>(CollectionModel::GroupBy_AlbumArtist)).toInt()),
|
||||||
CollectionModel::GroupBy(s.value(group_by(2), static_cast<int>(CollectionModel::GroupBy_AlbumDisc)).toInt()),
|
CollectionModel::GroupBy(s.value(group_by_key(2), static_cast<int>(CollectionModel::GroupBy_AlbumDisc)).toInt()),
|
||||||
CollectionModel::GroupBy(s.value(group_by(3), static_cast<int>(CollectionModel::GroupBy_None)).toInt())));
|
CollectionModel::GroupBy(s.value(group_by_key(3), static_cast<int>(CollectionModel::GroupBy_None)).toInt())), s.value(separate_albums_by_grouping_key(), false).toBool());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
model_->SetGroupBy(CollectionModel::Grouping(CollectionModel::GroupBy_AlbumArtist, CollectionModel::GroupBy_AlbumDisc, CollectionModel::GroupBy_None));
|
model_->SetGroupBy(CollectionModel::Grouping(CollectionModel::GroupBy_AlbumArtist, CollectionModel::GroupBy_AlbumDisc, CollectionModel::GroupBy_None), false);
|
||||||
}
|
}
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollectionFilterWidget::SetSettingsGroup(const QString &settings_group) {
|
||||||
|
|
||||||
|
settings_group_ = settings_group;
|
||||||
|
saved_groupings_settings_group_ = SavedGroupingManager::GetSavedGroupingsSettingsGroup(settings_group);
|
||||||
|
|
||||||
|
UpdateGroupByActions();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollectionFilterWidget::SetSettingsPrefix(const QString &prefix) {
|
||||||
|
|
||||||
|
settings_prefix_ = prefix;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionFilterWidget::ReloadSettings() {
|
void CollectionFilterWidget::ReloadSettings() {
|
||||||
@@ -198,21 +216,10 @@ void CollectionFilterWidget::ReloadSettings() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CollectionFilterWidget::group_by() {
|
QString CollectionFilterWidget::group_by_version() const {
|
||||||
|
|
||||||
if (settings_prefix_.isEmpty()) {
|
if (settings_prefix_.isEmpty()) {
|
||||||
return QString("group_by");
|
return "group_by_version";
|
||||||
}
|
|
||||||
else {
|
|
||||||
return QString("%1_group_by").arg(settings_prefix_);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QString CollectionFilterWidget::group_by_version() {
|
|
||||||
|
|
||||||
if (settings_prefix_.isEmpty()) {
|
|
||||||
return QString("group_by_version");
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return QString("%1_group_by_version").arg(settings_prefix_);
|
return QString("%1_group_by_version").arg(settings_prefix_);
|
||||||
@@ -220,7 +227,29 @@ QString CollectionFilterWidget::group_by_version() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CollectionFilterWidget::group_by(const int number) { return group_by() + QString::number(number); }
|
QString CollectionFilterWidget::group_by_key() const {
|
||||||
|
|
||||||
|
if (settings_prefix_.isEmpty()) {
|
||||||
|
return "group_by";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return QString("%1_group_by").arg(settings_prefix_);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CollectionFilterWidget::group_by_key(const int number) const { return group_by_key() + QString::number(number); }
|
||||||
|
|
||||||
|
QString CollectionFilterWidget::separate_albums_by_grouping_key() const {
|
||||||
|
|
||||||
|
if (settings_prefix_.isEmpty()) {
|
||||||
|
return "separate_albums_by_grouping";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return QString("%1_separate_albums_by_grouping").arg(settings_prefix_);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void CollectionFilterWidget::UpdateGroupByActions() {
|
void CollectionFilterWidget::UpdateGroupByActions() {
|
||||||
|
|
||||||
@@ -229,7 +258,7 @@ void CollectionFilterWidget::UpdateGroupByActions() {
|
|||||||
delete group_by_group_;
|
delete group_by_group_;
|
||||||
}
|
}
|
||||||
|
|
||||||
group_by_group_ = CreateGroupByActions(this);
|
group_by_group_ = CreateGroupByActions(saved_groupings_settings_group_, this);
|
||||||
group_by_menu_->clear();
|
group_by_menu_->clear();
|
||||||
group_by_menu_->addActions(group_by_group_->actions());
|
group_by_menu_->addActions(group_by_group_->actions());
|
||||||
QObject::connect(group_by_group_, &QActionGroup::triggered, this, &CollectionFilterWidget::GroupByClicked);
|
QObject::connect(group_by_group_, &QActionGroup::triggered, this, &CollectionFilterWidget::GroupByClicked);
|
||||||
@@ -239,8 +268,7 @@ void CollectionFilterWidget::UpdateGroupByActions() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QActionGroup *CollectionFilterWidget::CreateGroupByActions(const QString &saved_groupings_settings_group, QObject *parent) {
|
||||||
QActionGroup *CollectionFilterWidget::CreateGroupByActions(QObject *parent) {
|
|
||||||
|
|
||||||
QActionGroup *ret = new QActionGroup(parent);
|
QActionGroup *ret = new QActionGroup(parent);
|
||||||
|
|
||||||
@@ -267,9 +295,9 @@ QActionGroup *CollectionFilterWidget::CreateGroupByActions(QObject *parent) {
|
|||||||
sep1->setSeparator(true);
|
sep1->setSeparator(true);
|
||||||
ret->addAction(sep1);
|
ret->addAction(sep1);
|
||||||
|
|
||||||
// read saved groupings
|
// Read saved groupings
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(CollectionModel::kSavedGroupingsSettingsGroup);
|
s.beginGroup(saved_groupings_settings_group);
|
||||||
int version = s.value("version").toInt();
|
int version = s.value("version").toInt();
|
||||||
if (version == 1) {
|
if (version == 1) {
|
||||||
QStringList saved = s.childKeys();
|
QStringList saved = s.childKeys();
|
||||||
@@ -316,20 +344,38 @@ QAction *CollectionFilterWidget::CreateGroupByAction(const QString &text, QObjec
|
|||||||
|
|
||||||
void CollectionFilterWidget::SaveGroupBy() {
|
void CollectionFilterWidget::SaveGroupBy() {
|
||||||
|
|
||||||
QString text = QInputDialog::getText(this, tr("Grouping Name"), tr("Grouping name:"));
|
if (!model_) return;
|
||||||
if (!text.isEmpty() && model_) {
|
|
||||||
model_->SaveGrouping(text);
|
QString name = QInputDialog::getText(this, tr("Grouping Name"), tr("Grouping name:"));
|
||||||
UpdateGroupByActions();
|
if (name.isEmpty()) return;
|
||||||
|
|
||||||
|
qLog(Debug) << "Saving current grouping to" << name;
|
||||||
|
|
||||||
|
QSettings s;
|
||||||
|
if (settings_group_.isEmpty() || settings_group_ == CollectionSettingsPage::kSettingsGroup) {
|
||||||
|
s.beginGroup(SavedGroupingManager::kSavedGroupingsSettingsGroup);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
s.beginGroup(QString(SavedGroupingManager::kSavedGroupingsSettingsGroup) + "_" + settings_group_);
|
||||||
|
}
|
||||||
|
QByteArray buffer;
|
||||||
|
QDataStream datastream(&buffer, QIODevice::WriteOnly);
|
||||||
|
datastream << model_->GetGroupBy();
|
||||||
|
s.setValue("version", "1");
|
||||||
|
s.setValue(name, buffer);
|
||||||
|
s.endGroup();
|
||||||
|
|
||||||
|
UpdateGroupByActions();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionFilterWidget::ShowGroupingManager() {
|
void CollectionFilterWidget::ShowGroupingManager() {
|
||||||
|
|
||||||
if (!groupings_manager_) {
|
if (!groupings_manager_) {
|
||||||
groupings_manager_ = std::make_unique<SavedGroupingManager>();
|
groupings_manager_ = new SavedGroupingManager(saved_groupings_settings_group_, this);
|
||||||
|
QObject::connect(groupings_manager_, &SavedGroupingManager::UpdateGroupByActions, this, &CollectionFilterWidget::UpdateGroupByActions);
|
||||||
}
|
}
|
||||||
groupings_manager_->SetFilter(this);
|
|
||||||
groupings_manager_->UpdateModel();
|
groupings_manager_->UpdateModel();
|
||||||
groupings_manager_->show();
|
groupings_manager_->show();
|
||||||
|
|
||||||
@@ -366,16 +412,16 @@ void CollectionFilterWidget::GroupByClicked(QAction *action) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionFilterWidget::GroupingChanged(const CollectionModel::Grouping g) {
|
void CollectionFilterWidget::GroupingChanged(const CollectionModel::Grouping g, const bool separate_albums_by_grouping) {
|
||||||
|
|
||||||
if (!settings_group_.isEmpty()) {
|
if (!settings_group_.isEmpty()) {
|
||||||
// Save the settings
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(settings_group_);
|
s.beginGroup(settings_group_);
|
||||||
s.setValue(group_by_version(), 1);
|
s.setValue(group_by_version(), 1);
|
||||||
s.setValue(group_by(1), static_cast<int>(g[0]));
|
s.setValue(group_by_key(1), static_cast<int>(g[0]));
|
||||||
s.setValue(group_by(2), static_cast<int>(g[1]));
|
s.setValue(group_by_key(2), static_cast<int>(g[1]));
|
||||||
s.setValue(group_by(3), static_cast<int>(g[2]));
|
s.setValue(group_by_key(3), static_cast<int>(g[2]));
|
||||||
|
s.setValue(separate_albums_by_grouping_key(), separate_albums_by_grouping);
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,6 +432,10 @@ void CollectionFilterWidget::GroupingChanged(const CollectionModel::Grouping g)
|
|||||||
|
|
||||||
void CollectionFilterWidget::CheckCurrentGrouping(const CollectionModel::Grouping g) {
|
void CollectionFilterWidget::CheckCurrentGrouping(const CollectionModel::Grouping g) {
|
||||||
|
|
||||||
|
if (!group_by_group_) {
|
||||||
|
UpdateGroupByActions();
|
||||||
|
}
|
||||||
|
|
||||||
for (QAction *action : group_by_group_->actions()) {
|
for (QAction *action : group_by_group_->actions()) {
|
||||||
if (action->property("group_by").isNull()) continue;
|
if (action->property("group_by").isNull()) continue;
|
||||||
|
|
||||||
@@ -406,12 +456,12 @@ void CollectionFilterWidget::SetFilterHint(const QString &hint) {
|
|||||||
ui_->search_field->setPlaceholderText(hint);
|
ui_->search_field->setPlaceholderText(hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionFilterWidget::SetQueryMode(QueryOptions::QueryMode query_mode) {
|
void CollectionFilterWidget::SetFilterMode(CollectionFilterOptions::FilterMode filter_mode) {
|
||||||
|
|
||||||
ui_->search_field->clear();
|
ui_->search_field->clear();
|
||||||
ui_->search_field->setEnabled(query_mode == QueryOptions::QueryMode_All);
|
ui_->search_field->setEnabled(filter_mode == CollectionFilterOptions::FilterMode_All);
|
||||||
|
|
||||||
model_->SetFilterQueryMode(query_mode);
|
model_->SetFilterMode(filter_mode);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2019-2022, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -31,6 +32,7 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include "collectionquery.h"
|
#include "collectionquery.h"
|
||||||
|
#include "collectionqueryoptions.h"
|
||||||
#include "collectionmodel.h"
|
#include "collectionmodel.h"
|
||||||
|
|
||||||
class QTimer;
|
class QTimer;
|
||||||
@@ -60,9 +62,8 @@ class CollectionFilterWidget : public QWidget {
|
|||||||
|
|
||||||
void Init(CollectionModel *model);
|
void Init(CollectionModel *model);
|
||||||
|
|
||||||
static QActionGroup *CreateGroupByActions(QObject *parent);
|
static QActionGroup *CreateGroupByActions(const QString &saved_groupings_settings_group, QObject *parent);
|
||||||
|
|
||||||
void UpdateGroupByActions();
|
|
||||||
void SetFilterHint(const QString &hint);
|
void SetFilterHint(const QString &hint);
|
||||||
void SetApplyFilterToCollection(bool filter_applies_to_model) { filter_applies_to_model_ = filter_applies_to_model; }
|
void SetApplyFilterToCollection(bool filter_applies_to_model) { filter_applies_to_model_ = filter_applies_to_model; }
|
||||||
void SetDelayBehaviour(DelayBehaviour behaviour) { delay_behaviour_ = behaviour; }
|
void SetDelayBehaviour(DelayBehaviour behaviour) { delay_behaviour_ = behaviour; }
|
||||||
@@ -73,12 +74,13 @@ class CollectionFilterWidget : public QWidget {
|
|||||||
QMenu *menu() const { return collection_menu_; }
|
QMenu *menu() const { return collection_menu_; }
|
||||||
void AddMenuAction(QAction *action);
|
void AddMenuAction(QAction *action);
|
||||||
|
|
||||||
void SetSettingsGroup(const QString &group) { settings_group_ = group; }
|
void SetSettingsGroup(const QString &group);
|
||||||
void SetSettingsPrefix(const QString &prefix) { settings_prefix_ = prefix; }
|
void SetSettingsPrefix(const QString &prefix);
|
||||||
|
|
||||||
QString group_by();
|
QString group_by_version() const;
|
||||||
QString group_by_version();
|
QString group_by_key() const;
|
||||||
QString group_by(const int number);
|
QString group_by_key(const int number) const;
|
||||||
|
QString separate_albums_by_grouping_key() const;
|
||||||
|
|
||||||
void ReloadSettings();
|
void ReloadSettings();
|
||||||
|
|
||||||
@@ -86,7 +88,8 @@ class CollectionFilterWidget : public QWidget {
|
|||||||
void FocusSearchField();
|
void FocusSearchField();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void SetQueryMode(QueryOptions::QueryMode query_mode);
|
void UpdateGroupByActions();
|
||||||
|
void SetFilterMode(CollectionFilterOptions::FilterMode filter_mode);
|
||||||
void FocusOnFilter(QKeyEvent *e);
|
void FocusOnFilter(QKeyEvent *e);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@@ -99,7 +102,7 @@ class CollectionFilterWidget : public QWidget {
|
|||||||
void keyReleaseEvent(QKeyEvent *e) override;
|
void keyReleaseEvent(QKeyEvent *e) override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void GroupingChanged(const CollectionModel::Grouping g);
|
void GroupingChanged(const CollectionModel::Grouping g, const bool separate_albums_by_grouping);
|
||||||
void GroupByClicked(QAction *action);
|
void GroupByClicked(QAction *action);
|
||||||
void SaveGroupBy();
|
void SaveGroupBy();
|
||||||
void ShowGroupingManager();
|
void ShowGroupingManager();
|
||||||
@@ -115,8 +118,8 @@ class CollectionFilterWidget : public QWidget {
|
|||||||
Ui_CollectionFilterWidget *ui_;
|
Ui_CollectionFilterWidget *ui_;
|
||||||
CollectionModel *model_;
|
CollectionModel *model_;
|
||||||
|
|
||||||
std::unique_ptr<GroupByDialog> group_by_dialog_;
|
GroupByDialog *group_by_dialog_;
|
||||||
std::unique_ptr<SavedGroupingManager> groupings_manager_;
|
SavedGroupingManager *groupings_manager_;
|
||||||
|
|
||||||
QMenu *filter_age_menu_;
|
QMenu *filter_age_menu_;
|
||||||
QMenu *group_by_menu_;
|
QMenu *group_by_menu_;
|
||||||
@@ -130,6 +133,7 @@ class CollectionFilterWidget : public QWidget {
|
|||||||
DelayBehaviour delay_behaviour_;
|
DelayBehaviour delay_behaviour_;
|
||||||
|
|
||||||
QString settings_group_;
|
QString settings_group_;
|
||||||
|
QString saved_groupings_settings_group_;
|
||||||
QString settings_prefix_;
|
QString settings_prefix_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
@@ -45,10 +47,12 @@
|
|||||||
|
|
||||||
#include "core/simpletreemodel.h"
|
#include "core/simpletreemodel.h"
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
|
#include "core/sqlrow.h"
|
||||||
#include "covermanager/albumcoverloader.h"
|
#include "covermanager/albumcoverloader.h"
|
||||||
|
#include "collectionfilteroptions.h"
|
||||||
#include "collectionquery.h"
|
#include "collectionquery.h"
|
||||||
|
#include "collectionqueryoptions.h"
|
||||||
#include "collectionitem.h"
|
#include "collectionitem.h"
|
||||||
#include "sqlrow.h"
|
|
||||||
#include "covermanager/albumcoverloaderoptions.h"
|
#include "covermanager/albumcoverloaderoptions.h"
|
||||||
|
|
||||||
class QSettings;
|
class QSettings;
|
||||||
@@ -64,8 +68,6 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
|||||||
explicit CollectionModel(CollectionBackend *backend, Application *app, QObject *parent = nullptr);
|
explicit CollectionModel(CollectionBackend *backend, Application *app, QObject *parent = nullptr);
|
||||||
~CollectionModel() override;
|
~CollectionModel() override;
|
||||||
|
|
||||||
static const char *kSavedGroupingsSettingsGroup;
|
|
||||||
|
|
||||||
static const int kPrettyCoverSize;
|
static const int kPrettyCoverSize;
|
||||||
static const char *kPixmapDiskCacheDir;
|
static const char *kPixmapDiskCacheDir;
|
||||||
|
|
||||||
@@ -160,9 +162,6 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
|||||||
// Whether or not to show letters heading in the collection view
|
// Whether or not to show letters heading in the collection view
|
||||||
void set_show_dividers(const bool show_dividers);
|
void set_show_dividers(const bool show_dividers);
|
||||||
|
|
||||||
// Save the current grouping
|
|
||||||
void SaveGrouping(const QString &name);
|
|
||||||
|
|
||||||
// Reload settings.
|
// Reload settings.
|
||||||
void ReloadSettings();
|
void ReloadSettings();
|
||||||
|
|
||||||
@@ -195,20 +194,20 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
|||||||
void ExpandAll(CollectionItem *item = nullptr) const;
|
void ExpandAll(CollectionItem *item = nullptr) const;
|
||||||
|
|
||||||
const CollectionModel::Grouping GetGroupBy() const { return group_by_; }
|
const CollectionModel::Grouping GetGroupBy() const { return group_by_; }
|
||||||
void SetGroupBy(const CollectionModel::Grouping g);
|
void SetGroupBy(const CollectionModel::Grouping g, const std::optional<bool> separate_albums_by_grouping = std::optional<bool>());
|
||||||
|
|
||||||
static QString ContainerKey(const GroupBy type, const Song &song);
|
static QString ContainerKey(const GroupBy group_by, const bool separate_albums_by_grouping, const Song &song);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void TotalSongCountUpdated(int count);
|
void TotalSongCountUpdated(int count);
|
||||||
void TotalArtistCountUpdated(int count);
|
void TotalArtistCountUpdated(int count);
|
||||||
void TotalAlbumCountUpdated(int count);
|
void TotalAlbumCountUpdated(int count);
|
||||||
void GroupingChanged(CollectionModel::Grouping g);
|
void GroupingChanged(CollectionModel::Grouping g, bool separate_albums_by_grouping);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void SetFilterAge(const int age);
|
void SetFilterMode(CollectionFilterOptions::FilterMode filter_mode);
|
||||||
void SetFilterText(const QString &text);
|
void SetFilterAge(const int filter_age);
|
||||||
void SetFilterQueryMode(QueryOptions::QueryMode query_mode);
|
void SetFilterText(const QString &filter_text);
|
||||||
|
|
||||||
void Init(const bool async = true);
|
void Init(const bool async = true);
|
||||||
void Reset();
|
void Reset();
|
||||||
@@ -235,34 +234,35 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
|||||||
void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result);
|
void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Provides some optimisations for loading the list of items in the root.
|
// Provides some optimizations for loading the list of items in the root.
|
||||||
// This gets called a lot when filtering the playlist, so it's nice to be able to do it in a background thread.
|
// This gets called a lot when filtering the playlist, so it's nice to be able to do it in a background thread.
|
||||||
QueryResult RunQuery(CollectionItem *parent);
|
CollectionQueryOptions PrepareQuery(CollectionItem *parent);
|
||||||
|
QueryResult RunQuery(const CollectionFilterOptions &filter_options = CollectionFilterOptions(), const CollectionQueryOptions &query_options = CollectionQueryOptions());
|
||||||
void PostQuery(CollectionItem *parent, const QueryResult &result, const bool signal);
|
void PostQuery(CollectionItem *parent, const QueryResult &result, const bool signal);
|
||||||
|
|
||||||
bool HasCompilations(const QSqlDatabase &db, const CollectionQuery &query);
|
bool HasCompilations(const QSqlDatabase &db, const CollectionFilterOptions &filter_options, const CollectionQueryOptions &query_options);
|
||||||
|
|
||||||
void BeginReset();
|
void BeginReset();
|
||||||
|
|
||||||
// Functions for working with queries and creating items.
|
// Functions for working with queries and creating items.
|
||||||
// When the model is reset or when a node is lazy-loaded the Collection constructs a database query to populate the items.
|
// When the model is reset or when a node is lazy-loaded the Collection constructs a database query to populate the items.
|
||||||
// Filters are added for each parent item, restricting the songs returned to a particular album or artist for example.
|
// Filters are added for each parent item, restricting the songs returned to a particular album or artist for example.
|
||||||
static void InitQuery(const GroupBy type, CollectionQuery *q);
|
static void SetQueryColumnSpec(const GroupBy group_by, const bool separate_albums_by_grouping, CollectionQueryOptions *query_options);
|
||||||
static void FilterQuery(const GroupBy type, CollectionItem *item, CollectionQuery *q);
|
static void AddQueryWhere(const GroupBy group_by, const bool separate_albums_by_grouping, CollectionItem *item, CollectionQueryOptions *query_options);
|
||||||
|
|
||||||
// Items can be created either from a query that's been run to populate a node, or by a spontaneous SongsDiscovered emission from the backend.
|
// Items can be created either from a query that's been run to populate a node, or by a spontaneous SongsDiscovered emission from the backend.
|
||||||
CollectionItem *ItemFromQuery(const GroupBy type, const bool signal, const bool create_divider, CollectionItem *parent, const SqlRow &row, const int container_level);
|
CollectionItem *ItemFromQuery(const GroupBy group_by, const bool separate_albums_by_grouping, const bool signal, const bool create_divider, CollectionItem *parent, const SqlRow &row, const int container_level);
|
||||||
CollectionItem *ItemFromSong(const GroupBy type, const bool signal, const bool create_divider, CollectionItem *parent, const Song &s, const int container_level);
|
CollectionItem *ItemFromSong(const GroupBy group_by, const bool separate_albums_by_grouping, const bool signal, const bool create_divider, CollectionItem *parent, const Song &s, const int container_level);
|
||||||
|
|
||||||
// The "Various Artists" node is an annoying special case.
|
// The "Various Artists" node is an annoying special case.
|
||||||
CollectionItem *CreateCompilationArtistNode(const bool signal, CollectionItem *parent);
|
CollectionItem *CreateCompilationArtistNode(const bool signal, CollectionItem *parent);
|
||||||
|
|
||||||
// Helpers for ItemFromQuery and ItemFromSong
|
// Helpers for ItemFromQuery and ItemFromSong
|
||||||
CollectionItem *InitItem(const GroupBy type, const bool signal, CollectionItem *parent, const int container_level);
|
CollectionItem *InitItem(const GroupBy group_by, const bool signal, CollectionItem *parent, const int container_level);
|
||||||
void FinishItem(const GroupBy type, const bool signal, const bool create_divider, CollectionItem *parent, CollectionItem *item);
|
void FinishItem(const GroupBy group_by, const bool signal, const bool create_divider, CollectionItem *parent, CollectionItem *item);
|
||||||
|
|
||||||
static QString DividerKey(const GroupBy type, CollectionItem *item);
|
static QString DividerKey(const GroupBy group_by, CollectionItem *item);
|
||||||
static QString DividerDisplayText(const GroupBy type, const QString &key);
|
static QString DividerDisplayText(const GroupBy group_by, const QString &key);
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
static bool IsCompilationArtistNode(const CollectionItem *node) { return node == node->parent->compilation_artist_node_; }
|
static bool IsCompilationArtistNode(const CollectionItem *node) { return node == node->parent->compilation_artist_node_; }
|
||||||
@@ -282,8 +282,9 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
|||||||
int total_artist_count_;
|
int total_artist_count_;
|
||||||
int total_album_count_;
|
int total_album_count_;
|
||||||
|
|
||||||
QueryOptions query_options_;
|
CollectionFilterOptions filter_options_;
|
||||||
Grouping group_by_;
|
Grouping group_by_;
|
||||||
|
bool separate_albums_by_grouping_;
|
||||||
|
|
||||||
// Keyed on database ID
|
// Keyed on database ID
|
||||||
QMap<int, CollectionItem*> song_nodes_;
|
QMap<int, CollectionItem*> song_nodes_;
|
||||||
@@ -310,7 +311,7 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
|||||||
|
|
||||||
AlbumCoverLoaderOptions cover_loader_options_;
|
AlbumCoverLoaderOptions cover_loader_options_;
|
||||||
|
|
||||||
typedef QPair<CollectionItem*, QString> ItemAndCacheKey;
|
using ItemAndCacheKey = QPair<CollectionItem*, QString>;
|
||||||
QMap<quint64, ItemAndCacheKey> pending_art_;
|
QMap<quint64, ItemAndCacheKey> pending_art_;
|
||||||
QSet<QString> pending_cache_keys_;
|
QSet<QString> pending_cache_keys_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,16 +31,16 @@
|
|||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QSqlDatabase>
|
#include <QSqlDatabase>
|
||||||
#include <QSqlQuery>
|
#include <QSqlQuery>
|
||||||
#include <QSqlError>
|
|
||||||
|
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
|
#include "core/sqlquery.h"
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
|
|
||||||
#include "collectionquery.h"
|
#include "collectionquery.h"
|
||||||
|
#include "collectionfilteroptions.h"
|
||||||
|
#include "collectionqueryoptions.h"
|
||||||
|
|
||||||
QueryOptions::QueryOptions() : max_age_(-1), query_mode_(QueryMode_All) {}
|
CollectionQuery::CollectionQuery(const QSqlDatabase &db, const QString &songs_table, const QString &fts_table, const CollectionFilterOptions &filter_options)
|
||||||
|
|
||||||
CollectionQuery::CollectionQuery(const QSqlDatabase &db, const QString &songs_table, const QString &fts_table, const QueryOptions &options)
|
|
||||||
: QSqlQuery(db),
|
: QSqlQuery(db),
|
||||||
songs_table_(songs_table),
|
songs_table_(songs_table),
|
||||||
fts_table_(fts_table),
|
fts_table_(fts_table),
|
||||||
@@ -49,7 +49,7 @@ CollectionQuery::CollectionQuery(const QSqlDatabase &db, const QString &songs_ta
|
|||||||
duplicates_only_(false),
|
duplicates_only_(false),
|
||||||
limit_(-1) {
|
limit_(-1) {
|
||||||
|
|
||||||
if (!options.filter().isEmpty()) {
|
if (!filter_options.filter_text().isEmpty()) {
|
||||||
// We need to munge the filter text a little bit to get it to work as expected with sqlite's FTS5:
|
// We need to munge the filter text a little bit to get it to work as expected with sqlite's FTS5:
|
||||||
// 1) Append * to all tokens.
|
// 1) Append * to all tokens.
|
||||||
// 2) Prefix "fts" to column names.
|
// 2) Prefix "fts" to column names.
|
||||||
@@ -57,9 +57,9 @@ CollectionQuery::CollectionQuery(const QSqlDatabase &db, const QString &songs_ta
|
|||||||
|
|
||||||
// Split on whitespace
|
// Split on whitespace
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||||
QStringList tokens(options.filter().split(QRegularExpression("\\s+"), Qt::SkipEmptyParts));
|
QStringList tokens(filter_options.filter_text().split(QRegularExpression("\\s+"), Qt::SkipEmptyParts));
|
||||||
#else
|
#else
|
||||||
QStringList tokens(options.filter().split(QRegularExpression("\\s+"), QString::SkipEmptyParts));
|
QStringList tokens(filter_options.filter_text().split(QRegularExpression("\\s+"), QString::SkipEmptyParts));
|
||||||
#endif
|
#endif
|
||||||
QString query;
|
QString query;
|
||||||
for (QString token : tokens) {
|
for (QString token : tokens) {
|
||||||
@@ -100,49 +100,40 @@ CollectionQuery::CollectionQuery(const QSqlDatabase &db, const QString &songs_ta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.max_age() != -1) {
|
if (filter_options.max_age() != -1) {
|
||||||
qint64 cutoff = QDateTime::currentDateTime().toSecsSinceEpoch() - options.max_age();
|
qint64 cutoff = QDateTime::currentDateTime().toSecsSinceEpoch() - filter_options.max_age();
|
||||||
|
|
||||||
where_clauses_ << "ctime > ?";
|
where_clauses_ << "ctime > ?";
|
||||||
bound_values_ << cutoff;
|
bound_values_ << cutoff;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Currently you cannot use any QueryMode other than All and FTS at the same time.
|
// TODO: Currently you cannot use any FilterMode other than All and FTS at the same time.
|
||||||
// Joining songs, duplicated_songs and songs_fts all together takes a huge amount of time.
|
// Joining songs, duplicated_songs and songs_fts all together takes a huge amount of time.
|
||||||
// The query takes about 20 seconds on my machine then. Why?
|
// The query takes about 20 seconds on my machine then. Why?
|
||||||
// Untagged mode could work with additional filtering but I'm disabling it just to be consistent
|
// Untagged mode could work with additional filtering but I'm disabling it just to be consistent
|
||||||
// this way filtering is available only in the All mode.
|
// this way filtering is available only in the All mode.
|
||||||
// Remember though that when you fix the Duplicates + FTS cooperation, enable the filtering in both Duplicates and Untagged modes.
|
// Remember though that when you fix the Duplicates + FTS cooperation, enable the filtering in both Duplicates and Untagged modes.
|
||||||
duplicates_only_ = options.query_mode() == QueryOptions::QueryMode_Duplicates;
|
duplicates_only_ = filter_options.filter_mode() == CollectionFilterOptions::FilterMode_Duplicates;
|
||||||
|
|
||||||
if (options.query_mode() == QueryOptions::QueryMode_Untagged) {
|
if (filter_options.filter_mode() == CollectionFilterOptions::FilterMode_Untagged) {
|
||||||
where_clauses_ << "(artist = '' OR album = '' OR title ='')";
|
where_clauses_ << "(artist = '' OR album = '' OR title ='')";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CollectionQuery::GetInnerQuery() const {
|
|
||||||
return duplicates_only_
|
|
||||||
? QString(" INNER JOIN (select * from duplicated_songs) dsongs "
|
|
||||||
"ON (%songs_table.artist = dsongs.dup_artist "
|
|
||||||
"AND %songs_table.album = dsongs.dup_album "
|
|
||||||
"AND %songs_table.title = dsongs.dup_title) ")
|
|
||||||
: QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CollectionQuery::AddWhere(const QString &column, const QVariant &value, const QString &op) {
|
void CollectionQuery::AddWhere(const QString &column, const QVariant &value, const QString &op) {
|
||||||
|
|
||||||
// Ignore 'literal' for IN
|
// Ignore 'literal' for IN
|
||||||
if (op.compare("IN", Qt::CaseInsensitive) == 0) {
|
if (op.compare("IN", Qt::CaseInsensitive) == 0) {
|
||||||
QStringList values = value.toStringList();
|
QStringList values = value.toStringList();
|
||||||
QStringList final;
|
QStringList final_values;
|
||||||
final.reserve(values.count());
|
final_values.reserve(values.count());
|
||||||
for (const QString &single_value : values) {
|
for (const QString &single_value : values) {
|
||||||
final.append("?");
|
final_values.append("?");
|
||||||
bound_values_ << single_value;
|
bound_values_ << single_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
where_clauses_ << QString("%1 IN (" + final.join(",") + ")").arg(column);
|
where_clauses_ << QString("%1 IN (" + final_values.join(",") + ")").arg(column);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Do integers inline - sqlite seems to get confused when you pass integers to bound parameters
|
// Do integers inline - sqlite seems to get confused when you pass integers to bound parameters
|
||||||
@@ -187,6 +178,15 @@ void CollectionQuery::AddCompilationRequirement(const bool compilation) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString CollectionQuery::GetInnerQuery() const {
|
||||||
|
return duplicates_only_
|
||||||
|
? QString(" INNER JOIN (select * from duplicated_songs) dsongs "
|
||||||
|
"ON (%songs_table.artist = dsongs.dup_artist "
|
||||||
|
"AND %songs_table.album = dsongs.dup_album "
|
||||||
|
"AND %songs_table.title = dsongs.dup_title) ")
|
||||||
|
: QString();
|
||||||
|
}
|
||||||
|
|
||||||
bool CollectionQuery::Exec() {
|
bool CollectionQuery::Exec() {
|
||||||
|
|
||||||
QString sql;
|
QString sql;
|
||||||
@@ -213,32 +213,17 @@ bool CollectionQuery::Exec() {
|
|||||||
sql.replace("%fts_table_noprefix", fts_table_.section('.', -1, -1));
|
sql.replace("%fts_table_noprefix", fts_table_.section('.', -1, -1));
|
||||||
sql.replace("%fts_table", fts_table_);
|
sql.replace("%fts_table", fts_table_);
|
||||||
|
|
||||||
prepare(sql);
|
QSqlQuery::prepare(sql);
|
||||||
|
|
||||||
// Bind values
|
// Bind values
|
||||||
for (const QVariant &value : bound_values_) {
|
for (const QVariant &value : bound_values_) {
|
||||||
addBindValue(value);
|
QSqlQuery::addBindValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return exec();
|
return QSqlQuery::exec();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CollectionQuery::Next() { return next(); }
|
bool CollectionQuery::Next() { return QSqlQuery::next(); }
|
||||||
|
|
||||||
QVariant CollectionQuery::Value(const int column) const { return value(column); }
|
QVariant CollectionQuery::Value(const int column) const { return QSqlQuery::value(column); }
|
||||||
|
|
||||||
bool QueryOptions::Matches(const Song &song) const {
|
|
||||||
|
|
||||||
if (max_age_ != -1) {
|
|
||||||
const qint64 cutoff = QDateTime::currentDateTime().toSecsSinceEpoch() - max_age_;
|
|
||||||
if (song.ctime() <= cutoff) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!filter_.isNull()) {
|
|
||||||
return song.artist().contains(filter_, Qt::CaseInsensitive) || song.album().contains(filter_, Qt::CaseInsensitive) || song.title().contains(filter_, Qt::CaseInsensitive);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -28,75 +28,23 @@
|
|||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QMap>
|
|
||||||
#include <QSqlDatabase>
|
#include <QSqlDatabase>
|
||||||
#include <QSqlQuery>
|
#include <QSqlQuery>
|
||||||
|
|
||||||
class Song;
|
#include "collectionfilteroptions.h"
|
||||||
|
#include "collectionqueryoptions.h"
|
||||||
// This structure let's you customize behaviour of any CollectionQuery.
|
|
||||||
struct QueryOptions {
|
|
||||||
// Modes of CollectionQuery:
|
|
||||||
// - use the all songs table
|
|
||||||
// - use the duplicated songs view; by duplicated we mean those songs for which the (artist, album, title) tuple is found more than once in the songs table
|
|
||||||
// - use the untagged songs view; by untagged we mean those for which at least one of the (artist, album, title) tags is empty
|
|
||||||
// Please note that additional filtering based on FTS table (the filter attribute) won't work in Duplicates and Untagged modes.
|
|
||||||
enum QueryMode {
|
|
||||||
QueryMode_All,
|
|
||||||
QueryMode_Duplicates,
|
|
||||||
QueryMode_Untagged
|
|
||||||
};
|
|
||||||
|
|
||||||
QueryOptions();
|
|
||||||
|
|
||||||
bool Matches(const Song &song) const;
|
|
||||||
|
|
||||||
QString filter() const { return filter_; }
|
|
||||||
void set_filter(const QString &filter) {
|
|
||||||
filter_ = filter;
|
|
||||||
query_mode_ = QueryMode_All;
|
|
||||||
}
|
|
||||||
|
|
||||||
int max_age() const { return max_age_; }
|
|
||||||
void set_max_age(int max_age) { max_age_ = max_age; }
|
|
||||||
|
|
||||||
QueryMode query_mode() const { return query_mode_; }
|
|
||||||
void set_query_mode(QueryMode query_mode) {
|
|
||||||
query_mode_ = query_mode;
|
|
||||||
filter_ = QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString filter_;
|
|
||||||
int max_age_;
|
|
||||||
QueryMode query_mode_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CollectionQuery : public QSqlQuery {
|
class CollectionQuery : public QSqlQuery {
|
||||||
public:
|
public:
|
||||||
explicit CollectionQuery(const QSqlDatabase &db, const QString &songs_table, const QString &fts_table, const QueryOptions &options = QueryOptions());
|
explicit CollectionQuery(const QSqlDatabase &db, const QString &songs_table, const QString &fts_table, const CollectionFilterOptions &filter_options = CollectionFilterOptions());
|
||||||
|
|
||||||
// Sets contents of SELECT clause on the query (list of columns to get).
|
QVariant Value(const int column) const;
|
||||||
void SetColumnSpec(const QString &spec) { column_spec_ = spec; }
|
QVariant value(const int column) const { return Value(column); }
|
||||||
|
|
||||||
// Sets an ORDER BY clause on the query.
|
|
||||||
void SetOrderBy(const QString &order_by) { order_by_ = order_by; }
|
|
||||||
|
|
||||||
// Adds a fragment of WHERE clause. When executed, this Query will connect all the fragments with AND operator.
|
|
||||||
// Please note that IN operator expects a QStringList as value.
|
|
||||||
void AddWhere(const QString &column, const QVariant &value, const QString &op = "=");
|
|
||||||
void AddWhereArtist(const QVariant &value);
|
|
||||||
|
|
||||||
void SetWhereClauses(const QStringList &where_clauses) { where_clauses_ = where_clauses; }
|
|
||||||
void SetBoundValues(const QVariantList &bound_values) { bound_values_ = bound_values; }
|
|
||||||
void SetDuplicatesOnly(const bool duplicates_only) { duplicates_only_ = duplicates_only; }
|
|
||||||
void SetIncludeUnavailable(const bool include_unavailable) { include_unavailable_ = include_unavailable; }
|
|
||||||
void SetLimit(const int limit) { limit_ = limit; }
|
|
||||||
void AddCompilationRequirement(const bool compilation);
|
|
||||||
|
|
||||||
bool Exec();
|
bool Exec();
|
||||||
|
bool exec() { return QSqlQuery::exec(); }
|
||||||
|
|
||||||
bool Next();
|
bool Next();
|
||||||
QVariant Value(const int column) const;
|
|
||||||
|
|
||||||
QString column_spec() const { return column_spec_; }
|
QString column_spec() const { return column_spec_; }
|
||||||
QString order_by() const { return order_by_; }
|
QString order_by() const { return order_by_; }
|
||||||
@@ -107,6 +55,24 @@ class CollectionQuery : public QSqlQuery {
|
|||||||
bool duplicates_only() const { return duplicates_only_; }
|
bool duplicates_only() const { return duplicates_only_; }
|
||||||
int limit() const { return limit_; }
|
int limit() const { return limit_; }
|
||||||
|
|
||||||
|
// Sets contents of SELECT clause on the query (list of columns to get).
|
||||||
|
void SetColumnSpec(const QString &column_spec) { column_spec_ = column_spec; }
|
||||||
|
|
||||||
|
// Sets an ORDER BY clause on the query.
|
||||||
|
void SetOrderBy(const QString &order_by) { order_by_ = order_by; }
|
||||||
|
|
||||||
|
void SetWhereClauses(const QStringList &where_clauses) { where_clauses_ = where_clauses; }
|
||||||
|
// Adds a fragment of WHERE clause. When executed, this Query will connect all the fragments with AND operator.
|
||||||
|
// Please note that IN operator expects a QStringList as value.
|
||||||
|
void AddWhere(const QString &column, const QVariant &value, const QString &op = "=");
|
||||||
|
void AddWhereArtist(const QVariant &value);
|
||||||
|
|
||||||
|
void SetBoundValues(const QVariantList &bound_values) { bound_values_ = bound_values; }
|
||||||
|
void SetDuplicatesOnly(const bool duplicates_only) { duplicates_only_ = duplicates_only; }
|
||||||
|
void SetIncludeUnavailable(const bool include_unavailable) { include_unavailable_ = include_unavailable; }
|
||||||
|
void SetLimit(const int limit) { limit_ = limit; }
|
||||||
|
void AddCompilationRequirement(const bool compilation);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString GetInnerQuery() const;
|
QString GetInnerQuery() const;
|
||||||
|
|
||||||
|
|||||||
34
src/collection/collectionqueryoptions.cpp
Normal file
34
src/collection/collectionqueryoptions.cpp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Strawberry Music Player
|
||||||
|
* Copyright 2023, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
|
*
|
||||||
|
* Strawberry 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.
|
||||||
|
*
|
||||||
|
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "collectionqueryoptions.h"
|
||||||
|
#include "collectionfilteroptions.h"
|
||||||
|
|
||||||
|
CollectionQueryOptions::CollectionQueryOptions()
|
||||||
|
: compilation_requirement_(false),
|
||||||
|
query_have_compilations_(false) {}
|
||||||
|
|
||||||
|
void CollectionQueryOptions::AddWhere(const QString &column, const QVariant &value, const QString &op) {
|
||||||
|
|
||||||
|
where_clauses_ << Where(column, value, op);
|
||||||
|
|
||||||
|
}
|
||||||
57
src/collection/collectionqueryoptions.h
Normal file
57
src/collection/collectionqueryoptions.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Strawberry Music Player
|
||||||
|
* Copyright 2023, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
|
*
|
||||||
|
* Strawberry 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.
|
||||||
|
*
|
||||||
|
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COLLECTIONQUERYOPTIONS_H
|
||||||
|
#define COLLECTIONQUERYOPTIONS_H
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class CollectionQueryOptions {
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit CollectionQueryOptions();
|
||||||
|
|
||||||
|
struct Where {
|
||||||
|
explicit Where(const QString _column = QString(), const QVariant _value = QString(), const QString _op = QString()) : column(_column), value(_value), op(_op) {}
|
||||||
|
QString column;
|
||||||
|
QVariant value;
|
||||||
|
QString op;
|
||||||
|
};
|
||||||
|
|
||||||
|
QString column_spec() const { return column_spec_; }
|
||||||
|
bool compilation_requirement() const { return compilation_requirement_; }
|
||||||
|
bool query_have_compilations() const { return query_have_compilations_; }
|
||||||
|
|
||||||
|
void set_column_spec(const QString &column_spec) { column_spec_ = column_spec; }
|
||||||
|
void set_compilation_requirement(const bool compilation_requirement) { compilation_requirement_ = compilation_requirement; }
|
||||||
|
void set_query_have_compilations(const bool query_have_compilations) { query_have_compilations_ = query_have_compilations; }
|
||||||
|
|
||||||
|
QList<Where> where_clauses() const { return where_clauses_; }
|
||||||
|
void AddWhere(const QString &column, const QVariant &value, const QString &op = "=");
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString column_spec_;
|
||||||
|
bool compilation_requirement_;
|
||||||
|
bool query_have_compilations_;
|
||||||
|
QList<Where> where_clauses_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COLLECTIONQUERYOPTIONS_H
|
||||||
@@ -50,9 +50,9 @@
|
|||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "core/iconloader.h"
|
#include "core/iconloader.h"
|
||||||
#include "core/mimedata.h"
|
#include "core/mimedata.h"
|
||||||
#include "core/utilities.h"
|
|
||||||
#include "core/musicstorage.h"
|
#include "core/musicstorage.h"
|
||||||
#include "core/deletefiles.h"
|
#include "core/deletefiles.h"
|
||||||
|
#include "utilities/filemanagerutils.h"
|
||||||
#include "collection.h"
|
#include "collection.h"
|
||||||
#include "collectionbackend.h"
|
#include "collectionbackend.h"
|
||||||
#include "collectiondirectorymodel.h"
|
#include "collectiondirectorymodel.h"
|
||||||
|
|||||||
@@ -38,21 +38,19 @@
|
|||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QVariant>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QtDebug>
|
|
||||||
|
|
||||||
#include "core/filesystemwatcherinterface.h"
|
#include "core/filesystemwatcherinterface.h"
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
#include "core/timeconstants.h"
|
|
||||||
#include "core/tagreaderclient.h"
|
#include "core/tagreaderclient.h"
|
||||||
#include "core/taskmanager.h"
|
#include "core/taskmanager.h"
|
||||||
#include "core/imageutils.h"
|
#include "utilities/imageutils.h"
|
||||||
#include "directory.h"
|
#include "utilities/timeconstants.h"
|
||||||
|
#include "collectiondirectory.h"
|
||||||
#include "collectionbackend.h"
|
#include "collectionbackend.h"
|
||||||
#include "collectionwatcher.h"
|
#include "collectionwatcher.h"
|
||||||
#include "playlistparsers/cueparser.h"
|
#include "playlistparsers/cueparser.h"
|
||||||
@@ -82,6 +80,7 @@ CollectionWatcher::CollectionWatcher(Song::Source source, QObject *parent)
|
|||||||
song_tracking_(false),
|
song_tracking_(false),
|
||||||
mark_songs_unavailable_(source_ == Song::Source_Collection),
|
mark_songs_unavailable_(source_ == Song::Source_Collection),
|
||||||
expire_unavailable_songs_days_(60),
|
expire_unavailable_songs_days_(60),
|
||||||
|
overwrite_playcount_(false),
|
||||||
overwrite_rating_(false),
|
overwrite_rating_(false),
|
||||||
stop_requested_(false),
|
stop_requested_(false),
|
||||||
abort_requested_(false),
|
abort_requested_(false),
|
||||||
@@ -153,6 +152,7 @@ void CollectionWatcher::ReloadSettings() {
|
|||||||
mark_songs_unavailable_ = false;
|
mark_songs_unavailable_ = false;
|
||||||
}
|
}
|
||||||
expire_unavailable_songs_days_ = s.value("expire_unavailable_songs", 60).toInt();
|
expire_unavailable_songs_days_ = s.value("expire_unavailable_songs", 60).toInt();
|
||||||
|
overwrite_playcount_ = s.value("overwrite_playcount", false).toBool();
|
||||||
overwrite_rating_ = s.value("overwrite_rating", false).toBool();
|
overwrite_rating_ = s.value("overwrite_rating", false).toBool();
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
@@ -167,15 +167,15 @@ void CollectionWatcher::ReloadSettings() {
|
|||||||
}
|
}
|
||||||
else if (monitor_ && !was_monitoring_before) {
|
else if (monitor_ && !was_monitoring_before) {
|
||||||
// Add all directories to all QFileSystemWatchers again
|
// Add all directories to all QFileSystemWatchers again
|
||||||
for (const Directory &dir : std::as_const(watched_dirs_)) {
|
for (const CollectionDirectory &dir : std::as_const(watched_dirs_)) {
|
||||||
SubdirectoryList subdirs = backend_->SubdirsInDirectory(dir.id);
|
CollectionSubdirectoryList subdirs = backend_->SubdirsInDirectory(dir.id);
|
||||||
for (const Subdirectory &subdir : subdirs) {
|
for (const CollectionSubdirectory &subdir : subdirs) {
|
||||||
AddWatch(dir, subdir.path);
|
AddWatch(dir, subdir.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mark_songs_unavailable_ && !periodic_scan_timer_->isActive()) {
|
if (monitor_ && scan_on_startup_ && mark_songs_unavailable_ && !periodic_scan_timer_->isActive()) {
|
||||||
periodic_scan_timer_->start();
|
periodic_scan_timer_->start();
|
||||||
}
|
}
|
||||||
else if (!mark_songs_unavailable_ && periodic_scan_timer_->isActive()) {
|
else if (!mark_songs_unavailable_ && periodic_scan_timer_->isActive()) {
|
||||||
@@ -272,7 +272,7 @@ void CollectionWatcher::ScanTransaction::CommitNewOrUpdatedSongs() {
|
|||||||
touched_subdirs.clear();
|
touched_subdirs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const Subdirectory &subdir : deleted_subdirs) {
|
for (const CollectionSubdirectory &subdir : deleted_subdirs) {
|
||||||
if (watcher_->watched_dirs_.contains(dir_)) {
|
if (watcher_->watched_dirs_.contains(dir_)) {
|
||||||
watcher_->RemoveWatch(watcher_->watched_dirs_[dir_], subdir);
|
watcher_->RemoveWatch(watcher_->watched_dirs_[dir_], subdir);
|
||||||
}
|
}
|
||||||
@@ -281,7 +281,7 @@ void CollectionWatcher::ScanTransaction::CommitNewOrUpdatedSongs() {
|
|||||||
|
|
||||||
if (watcher_->monitor_) {
|
if (watcher_->monitor_) {
|
||||||
// Watch the new subdirectories
|
// Watch the new subdirectories
|
||||||
for (const Subdirectory &subdir : new_subdirs) {
|
for (const CollectionSubdirectory &subdir : new_subdirs) {
|
||||||
if (watcher_->watched_dirs_.contains(dir_)) {
|
if (watcher_->watched_dirs_.contains(dir_)) {
|
||||||
watcher_->AddWatch(watcher_->watched_dirs_[dir_], subdir.path);
|
watcher_->AddWatch(watcher_->watched_dirs_[dir_], subdir.path);
|
||||||
}
|
}
|
||||||
@@ -329,7 +329,7 @@ bool CollectionWatcher::ScanTransaction::HasSongsWithMissingFingerprint(const QS
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionWatcher::ScanTransaction::SetKnownSubdirs(const SubdirectoryList &subdirs) {
|
void CollectionWatcher::ScanTransaction::SetKnownSubdirs(const CollectionSubdirectoryList &subdirs) {
|
||||||
|
|
||||||
known_subdirs_ = subdirs;
|
known_subdirs_ = subdirs;
|
||||||
known_subdirs_dirty_ = false;
|
known_subdirs_dirty_ = false;
|
||||||
@@ -342,18 +342,18 @@ bool CollectionWatcher::ScanTransaction::HasSeenSubdir(const QString &path) {
|
|||||||
SetKnownSubdirs(watcher_->backend_->SubdirsInDirectory(dir_));
|
SetKnownSubdirs(watcher_->backend_->SubdirsInDirectory(dir_));
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::any_of(known_subdirs_.begin(), known_subdirs_.end(), [path](const Subdirectory &subdir) { return subdir.path == path && subdir.mtime != 0; });
|
return std::any_of(known_subdirs_.begin(), known_subdirs_.end(), [path](const CollectionSubdirectory &subdir) { return subdir.path == path && subdir.mtime != 0; });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SubdirectoryList CollectionWatcher::ScanTransaction::GetImmediateSubdirs(const QString &path) {
|
CollectionSubdirectoryList CollectionWatcher::ScanTransaction::GetImmediateSubdirs(const QString &path) {
|
||||||
|
|
||||||
if (known_subdirs_dirty_) {
|
if (known_subdirs_dirty_) {
|
||||||
SetKnownSubdirs(watcher_->backend_->SubdirsInDirectory(dir_));
|
SetKnownSubdirs(watcher_->backend_->SubdirsInDirectory(dir_));
|
||||||
}
|
}
|
||||||
|
|
||||||
SubdirectoryList ret;
|
CollectionSubdirectoryList ret;
|
||||||
for (const Subdirectory &subdir : known_subdirs_) {
|
for (const CollectionSubdirectory &subdir : known_subdirs_) {
|
||||||
if (subdir.path.left(subdir.path.lastIndexOf(QDir::separator())) == path && subdir.mtime != 0) {
|
if (subdir.path.left(subdir.path.lastIndexOf(QDir::separator())) == path && subdir.mtime != 0) {
|
||||||
ret << subdir;
|
ret << subdir;
|
||||||
}
|
}
|
||||||
@@ -363,7 +363,7 @@ SubdirectoryList CollectionWatcher::ScanTransaction::GetImmediateSubdirs(const Q
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SubdirectoryList CollectionWatcher::ScanTransaction::GetAllSubdirs() {
|
CollectionSubdirectoryList CollectionWatcher::ScanTransaction::GetAllSubdirs() {
|
||||||
|
|
||||||
if (known_subdirs_dirty_) {
|
if (known_subdirs_dirty_) {
|
||||||
SetKnownSubdirs(watcher_->backend_->SubdirsInDirectory(dir_));
|
SetKnownSubdirs(watcher_->backend_->SubdirsInDirectory(dir_));
|
||||||
@@ -373,7 +373,7 @@ SubdirectoryList CollectionWatcher::ScanTransaction::GetAllSubdirs() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionWatcher::AddDirectory(const Directory &dir, const SubdirectoryList &subdirs) {
|
void CollectionWatcher::AddDirectory(const CollectionDirectory &dir, const CollectionSubdirectoryList &subdirs) {
|
||||||
|
|
||||||
stop_requested_ = false;
|
stop_requested_ = false;
|
||||||
|
|
||||||
@@ -385,7 +385,7 @@ void CollectionWatcher::AddDirectory(const Directory &dir, const SubdirectoryLis
|
|||||||
const quint64 files_count = FilesCountForPath(&transaction, dir.path);
|
const quint64 files_count = FilesCountForPath(&transaction, dir.path);
|
||||||
transaction.SetKnownSubdirs(subdirs);
|
transaction.SetKnownSubdirs(subdirs);
|
||||||
transaction.AddToProgressMax(files_count);
|
transaction.AddToProgressMax(files_count);
|
||||||
ScanSubdirectory(dir.path, Subdirectory(), files_count, &transaction);
|
ScanSubdirectory(dir.path, CollectionSubdirectory(), files_count, &transaction);
|
||||||
last_scan_time_ = QDateTime::currentDateTime().toSecsSinceEpoch();
|
last_scan_time_ = QDateTime::currentDateTime().toSecsSinceEpoch();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -395,7 +395,7 @@ void CollectionWatcher::AddDirectory(const Directory &dir, const SubdirectoryLis
|
|||||||
const quint64 files_count = FilesCountForSubdirs(&transaction, subdirs, subdir_files_count);
|
const quint64 files_count = FilesCountForSubdirs(&transaction, subdirs, subdir_files_count);
|
||||||
transaction.SetKnownSubdirs(subdirs);
|
transaction.SetKnownSubdirs(subdirs);
|
||||||
transaction.AddToProgressMax(files_count);
|
transaction.AddToProgressMax(files_count);
|
||||||
for (const Subdirectory &subdir : subdirs) {
|
for (const CollectionSubdirectory &subdir : subdirs) {
|
||||||
if (stop_requested_ || abort_requested_) break;
|
if (stop_requested_ || abort_requested_) break;
|
||||||
|
|
||||||
if (scan_on_startup_) ScanSubdirectory(subdir.path, subdir, subdir_files_count[subdir.path], &transaction);
|
if (scan_on_startup_) ScanSubdirectory(subdir.path, subdir, subdir_files_count[subdir.path], &transaction);
|
||||||
@@ -411,14 +411,14 @@ void CollectionWatcher::AddDirectory(const Directory &dir, const SubdirectoryLis
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory &subdir, const quint64 files_count, ScanTransaction *t, const bool force_noincremental) {
|
void CollectionWatcher::ScanSubdirectory(const QString &path, const CollectionSubdirectory &subdir, const quint64 files_count, ScanTransaction *t, const bool force_noincremental) {
|
||||||
|
|
||||||
QFileInfo path_info(path);
|
QFileInfo path_info(path);
|
||||||
|
|
||||||
// Do not scan symlinked dirs that are already in collection
|
// Do not scan symlinked dirs that are already in collection
|
||||||
if (path_info.isSymLink()) {
|
if (path_info.isSymLink()) {
|
||||||
QString real_path = path_info.symLinkTarget();
|
QString real_path = path_info.symLinkTarget();
|
||||||
for (const Directory &dir : std::as_const(watched_dirs_)) {
|
for (const CollectionDirectory &dir : std::as_const(watched_dirs_)) {
|
||||||
if (real_path.startsWith(dir.path)) {
|
if (real_path.startsWith(dir.path)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -440,12 +440,12 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
|
|||||||
|
|
||||||
QMap<QString, QStringList> album_art;
|
QMap<QString, QStringList> album_art;
|
||||||
QStringList files_on_disk;
|
QStringList files_on_disk;
|
||||||
SubdirectoryList my_new_subdirs;
|
CollectionSubdirectoryList my_new_subdirs;
|
||||||
|
|
||||||
// If a directory is moved then only its parent gets a changed notification, so we need to look and see if any of our children don't exist any more.
|
// If a directory is moved then only its parent gets a changed notification, so we need to look and see if any of our children don't exist anymore.
|
||||||
// If one has been removed, "rescan" it to get the deleted songs
|
// If one has been removed, "rescan" it to get the deleted songs
|
||||||
SubdirectoryList previous_subdirs = t->GetImmediateSubdirs(path);
|
CollectionSubdirectoryList previous_subdirs = t->GetImmediateSubdirs(path);
|
||||||
for (const Subdirectory &prev_subdir : previous_subdirs) {
|
for (const CollectionSubdirectory &prev_subdir : previous_subdirs) {
|
||||||
if (!QFile::exists(prev_subdir.path) && prev_subdir.path != path) {
|
if (!QFile::exists(prev_subdir.path) && prev_subdir.path != path) {
|
||||||
ScanSubdirectory(prev_subdir.path, prev_subdir, 0, t, true);
|
ScanSubdirectory(prev_subdir.path, prev_subdir, 0, t, true);
|
||||||
}
|
}
|
||||||
@@ -462,8 +462,8 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
|
|||||||
|
|
||||||
if (child_info.isDir()) {
|
if (child_info.isDir()) {
|
||||||
if (!t->HasSeenSubdir(child)) {
|
if (!t->HasSeenSubdir(child)) {
|
||||||
// We haven't seen this subdirectory before - add it to a list and later we'll tell the backend about it and scan it.
|
// We haven't seen this subdirectory before - add it to a list, and later we'll tell the backend about it and scan it.
|
||||||
Subdirectory new_subdir;
|
CollectionSubdirectory new_subdir;
|
||||||
new_subdir.directory_id = -1;
|
new_subdir.directory_id = -1;
|
||||||
new_subdir.path = child;
|
new_subdir.path = child;
|
||||||
new_subdir.mtime = child_info.lastModified().toSecsSinceEpoch();
|
new_subdir.mtime = child_info.lastModified().toSecsSinceEpoch();
|
||||||
@@ -676,7 +676,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add this subdir to the new or touched list
|
// Add this subdir to the new or touched list
|
||||||
Subdirectory updated_subdir;
|
CollectionSubdirectory updated_subdir;
|
||||||
updated_subdir.directory_id = t->dir();
|
updated_subdir.directory_id = t->dir();
|
||||||
updated_subdir.mtime = path_info.exists() ? path_info.lastModified().toSecsSinceEpoch() : 0;
|
updated_subdir.mtime = path_info.exists() ? path_info.lastModified().toSecsSinceEpoch() : 0;
|
||||||
updated_subdir.path = path;
|
updated_subdir.path = path;
|
||||||
@@ -688,12 +688,12 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
|
|||||||
t->touched_subdirs << updated_subdir;
|
t->touched_subdirs << updated_subdir;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updated_subdir.mtime == 0) { // Subdirectory deleted, mark it for removal from the watcher.
|
if (updated_subdir.mtime == 0) { // CollectionSubdirectory deleted, mark it for removal from the watcher.
|
||||||
t->deleted_subdirs << updated_subdir;
|
t->deleted_subdirs << updated_subdir;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recurse into the new subdirs that we found
|
// Recurse into the new subdirs that we found
|
||||||
for (const Subdirectory &my_new_subdir : my_new_subdirs) {
|
for (const CollectionSubdirectory &my_new_subdir : my_new_subdirs) {
|
||||||
if (stop_requested_ || abort_requested_) return;
|
if (stop_requested_ || abort_requested_) return;
|
||||||
ScanSubdirectory(my_new_subdir.path, my_new_subdir, 0, t, true);
|
ScanSubdirectory(my_new_subdir.path, my_new_subdir, 0, t, true);
|
||||||
}
|
}
|
||||||
@@ -734,7 +734,7 @@ void CollectionWatcher::UpdateCueAssociatedSongs(const QString &file,
|
|||||||
const Song matching_cue_song = sections_map[new_cue_song.beginning_nanosec()];
|
const Song matching_cue_song = sections_map[new_cue_song.beginning_nanosec()];
|
||||||
new_cue_song.set_id(matching_cue_song.id());
|
new_cue_song.set_id(matching_cue_song.id());
|
||||||
if (!new_cue_song.has_embedded_cover()) new_cue_song.set_art_automatic(image);
|
if (!new_cue_song.has_embedded_cover()) new_cue_song.set_art_automatic(image);
|
||||||
new_cue_song.MergeUserSetData(matching_cue_song, true);
|
new_cue_song.MergeUserSetData(matching_cue_song, true, true);
|
||||||
AddChangedSong(file, matching_cue_song, new_cue_song, t);
|
AddChangedSong(file, matching_cue_song, new_cue_song, t);
|
||||||
used_ids.insert(matching_cue_song.id());
|
used_ids.insert(matching_cue_song.id());
|
||||||
}
|
}
|
||||||
@@ -759,7 +759,7 @@ void CollectionWatcher::UpdateNonCueAssociatedSong(const QString &file,
|
|||||||
const bool cue_deleted,
|
const bool cue_deleted,
|
||||||
ScanTransaction *t) {
|
ScanTransaction *t) {
|
||||||
|
|
||||||
// If a CUE got deleted, we turn it's first section into the new 'raw' (cueless) song and we just remove the rest of the sections from the collection
|
// If a CUE got deleted, we turn it's first section into the new 'raw' (cueless) song, and we just remove the rest of the sections from the collection
|
||||||
const Song &matching_song = matching_songs.first();
|
const Song &matching_song = matching_songs.first();
|
||||||
if (cue_deleted) {
|
if (cue_deleted) {
|
||||||
for (const Song &song : matching_songs) {
|
for (const Song &song : matching_songs) {
|
||||||
@@ -777,7 +777,7 @@ void CollectionWatcher::UpdateNonCueAssociatedSong(const QString &file,
|
|||||||
song_on_disk.set_id(matching_song.id());
|
song_on_disk.set_id(matching_song.id());
|
||||||
song_on_disk.set_fingerprint(fingerprint);
|
song_on_disk.set_fingerprint(fingerprint);
|
||||||
if (!song_on_disk.has_embedded_cover()) song_on_disk.set_art_automatic(image);
|
if (!song_on_disk.has_embedded_cover()) song_on_disk.set_art_automatic(image);
|
||||||
song_on_disk.MergeUserSetData(matching_song, !overwrite_rating_);
|
song_on_disk.MergeUserSetData(matching_song, !overwrite_playcount_, !overwrite_rating_);
|
||||||
AddChangedSong(file, matching_song, song_on_disk, t);
|
AddChangedSong(file, matching_song, song_on_disk, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -803,7 +803,7 @@ SongList CollectionWatcher::ScanNewFile(const QString &file, const QString &path
|
|||||||
|
|
||||||
// Ignore FILEs pointing to other media files.
|
// Ignore FILEs pointing to other media files.
|
||||||
// Also, watch out for incorrect media files.
|
// Also, watch out for incorrect media files.
|
||||||
// Playlist parser for CUEs considers every entry in sheet valid and we don't want invalid media getting into collection!
|
// Playlist parser for CUEs considers every entry in sheet valid, and we don't want invalid media getting into collection!
|
||||||
QString file_nfd = file.normalized(QString::NormalizationForm_D);
|
QString file_nfd = file.normalized(QString::NormalizationForm_D);
|
||||||
SongList cue_congs = cue_parser_->Load(&cue_file, matching_cue, path, false);
|
SongList cue_congs = cue_parser_->Load(&cue_file, matching_cue, path, false);
|
||||||
cue_file.close();
|
cue_file.close();
|
||||||
@@ -897,7 +897,7 @@ quint64 CollectionWatcher::GetMtimeForCue(const QString &cue_path) {
|
|||||||
return cue_last_modified.isValid() ? cue_last_modified.toSecsSinceEpoch() : 0;
|
return cue_last_modified.isValid() ? cue_last_modified.toSecsSinceEpoch() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionWatcher::AddWatch(const Directory &dir, const QString &path) {
|
void CollectionWatcher::AddWatch(const CollectionDirectory &dir, const QString &path) {
|
||||||
|
|
||||||
if (!QFile::exists(path)) return;
|
if (!QFile::exists(path)) return;
|
||||||
|
|
||||||
@@ -907,7 +907,7 @@ void CollectionWatcher::AddWatch(const Directory &dir, const QString &path) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionWatcher::RemoveWatch(const Directory &dir, const Subdirectory &subdir) {
|
void CollectionWatcher::RemoveWatch(const CollectionDirectory &dir, const CollectionSubdirectory &subdir) {
|
||||||
|
|
||||||
QStringList subdir_paths = subdir_mapping_.keys(dir);
|
QStringList subdir_paths = subdir_mapping_.keys(dir);
|
||||||
for (const QString &subdir_path : subdir_paths) {
|
for (const QString &subdir_path : subdir_paths) {
|
||||||
@@ -919,7 +919,7 @@ void CollectionWatcher::RemoveWatch(const Directory &dir, const Subdirectory &su
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionWatcher::RemoveDirectory(const Directory &dir) {
|
void CollectionWatcher::RemoveDirectory(const CollectionDirectory &dir) {
|
||||||
|
|
||||||
rescan_queue_.remove(dir.id);
|
rescan_queue_.remove(dir.id);
|
||||||
watched_dirs_.remove(dir.id);
|
watched_dirs_.remove(dir.id);
|
||||||
@@ -979,11 +979,11 @@ bool CollectionWatcher::FindSongsByFingerprint(const QString &file, const SongLi
|
|||||||
void CollectionWatcher::DirectoryChanged(const QString &subdir) {
|
void CollectionWatcher::DirectoryChanged(const QString &subdir) {
|
||||||
|
|
||||||
// Find what dir it was in
|
// Find what dir it was in
|
||||||
QHash<QString, Directory>::const_iterator it = subdir_mapping_.constFind(subdir);
|
QHash<QString, CollectionDirectory>::const_iterator it = subdir_mapping_.constFind(subdir);
|
||||||
if (it == subdir_mapping_.constEnd()) {
|
if (it == subdir_mapping_.constEnd()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Directory dir = *it;
|
CollectionDirectory dir = *it;
|
||||||
|
|
||||||
qLog(Debug) << "Subdir" << subdir << "changed under directory" << dir.path << "id" << dir.id;
|
qLog(Debug) << "Subdir" << subdir << "changed under directory" << dir.path << "id" << dir.id;
|
||||||
|
|
||||||
@@ -1010,7 +1010,7 @@ void CollectionWatcher::RescanPathsNow() {
|
|||||||
|
|
||||||
for (const QString &path : rescan_queue_[dir]) {
|
for (const QString &path : rescan_queue_[dir]) {
|
||||||
if (stop_requested_ || abort_requested_) break;
|
if (stop_requested_ || abort_requested_) break;
|
||||||
Subdirectory subdir;
|
CollectionSubdirectory subdir;
|
||||||
subdir.directory_id = dir;
|
subdir.directory_id = dir;
|
||||||
subdir.mtime = 0;
|
subdir.mtime = 0;
|
||||||
subdir.path = path;
|
subdir.path = path;
|
||||||
@@ -1154,7 +1154,7 @@ void CollectionWatcher::RescanTracksNow() {
|
|||||||
qLog(Debug) << "Song" << song.title() << "dir id" << song.directory_id() << "dir" << songdir;
|
qLog(Debug) << "Song" << song.title() << "dir id" << song.directory_id() << "dir" << songdir;
|
||||||
ScanTransaction transaction(this, song.directory_id(), false, false, mark_songs_unavailable_);
|
ScanTransaction transaction(this, song.directory_id(), false, false, mark_songs_unavailable_);
|
||||||
quint64 files_count = FilesCountForPath(&transaction, songdir);
|
quint64 files_count = FilesCountForPath(&transaction, songdir);
|
||||||
ScanSubdirectory(songdir, Subdirectory(), files_count, &transaction);
|
ScanSubdirectory(songdir, CollectionSubdirectory(), files_count, &transaction);
|
||||||
scanned_dirs << songdir;
|
scanned_dirs << songdir;
|
||||||
emit CompilationsNeedUpdating();
|
emit CompilationsNeedUpdating();
|
||||||
}
|
}
|
||||||
@@ -1171,16 +1171,16 @@ void CollectionWatcher::PerformScan(const bool incremental, const bool ignore_mt
|
|||||||
|
|
||||||
stop_requested_ = false;
|
stop_requested_ = false;
|
||||||
|
|
||||||
for (const Directory &dir : std::as_const(watched_dirs_)) {
|
for (const CollectionDirectory &dir : std::as_const(watched_dirs_)) {
|
||||||
|
|
||||||
if (stop_requested_ || abort_requested_) break;
|
if (stop_requested_ || abort_requested_) break;
|
||||||
|
|
||||||
ScanTransaction transaction(this, dir.id, incremental, ignore_mtimes, mark_songs_unavailable_);
|
ScanTransaction transaction(this, dir.id, incremental, ignore_mtimes, mark_songs_unavailable_);
|
||||||
SubdirectoryList subdirs(transaction.GetAllSubdirs());
|
CollectionSubdirectoryList subdirs(transaction.GetAllSubdirs());
|
||||||
|
|
||||||
if (subdirs.isEmpty()) {
|
if (subdirs.isEmpty()) {
|
||||||
qLog(Debug) << "Collection directory wasn't in subdir list.";
|
qLog(Debug) << "Collection directory wasn't in subdir list.";
|
||||||
Subdirectory subdir;
|
CollectionSubdirectory subdir;
|
||||||
subdir.path = dir.path;
|
subdir.path = dir.path;
|
||||||
subdir.directory_id = dir.id;
|
subdir.directory_id = dir.id;
|
||||||
subdirs << subdir;
|
subdirs << subdir;
|
||||||
@@ -1190,7 +1190,7 @@ void CollectionWatcher::PerformScan(const bool incremental, const bool ignore_mt
|
|||||||
quint64 files_count = FilesCountForSubdirs(&transaction, subdirs, subdir_files_count);
|
quint64 files_count = FilesCountForSubdirs(&transaction, subdirs, subdir_files_count);
|
||||||
transaction.AddToProgressMax(files_count);
|
transaction.AddToProgressMax(files_count);
|
||||||
|
|
||||||
for (const Subdirectory &subdir : subdirs) {
|
for (const CollectionSubdirectory &subdir : subdirs) {
|
||||||
if (stop_requested_ || abort_requested_) break;
|
if (stop_requested_ || abort_requested_) break;
|
||||||
ScanSubdirectory(subdir.path, subdir, subdir_files_count[subdir.path], &transaction);
|
ScanSubdirectory(subdir.path, subdir, subdir_files_count[subdir.path], &transaction);
|
||||||
}
|
}
|
||||||
@@ -1217,7 +1217,7 @@ quint64 CollectionWatcher::FilesCountForPath(ScanTransaction *t, const QString &
|
|||||||
if (path_info.isDir()) {
|
if (path_info.isDir()) {
|
||||||
if (path_info.isSymLink()) {
|
if (path_info.isSymLink()) {
|
||||||
QString real_path = path_info.symLinkTarget();
|
QString real_path = path_info.symLinkTarget();
|
||||||
for (const Directory &dir : std::as_const(watched_dirs_)) {
|
for (const CollectionDirectory &dir : std::as_const(watched_dirs_)) {
|
||||||
if (real_path.startsWith(dir.path)) {
|
if (real_path.startsWith(dir.path)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1239,10 +1239,10 @@ quint64 CollectionWatcher::FilesCountForPath(ScanTransaction *t, const QString &
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 CollectionWatcher::FilesCountForSubdirs(ScanTransaction *t, const SubdirectoryList &subdirs, QMap<QString, quint64> &subdir_files_count) {
|
quint64 CollectionWatcher::FilesCountForSubdirs(ScanTransaction *t, const CollectionSubdirectoryList &subdirs, QMap<QString, quint64> &subdir_files_count) {
|
||||||
|
|
||||||
quint64 i = 0;
|
quint64 i = 0;
|
||||||
for (const Subdirectory &subdir : subdirs) {
|
for (const CollectionSubdirectory &subdir : subdirs) {
|
||||||
if (stop_requested_ || abort_requested_) break;
|
if (stop_requested_ || abort_requested_) break;
|
||||||
const quint64 files_count = FilesCountForPath(t, subdir.path);
|
const quint64 files_count = FilesCountForPath(t, subdir.path);
|
||||||
subdir_files_count[subdir.path] = files_count;
|
subdir_files_count[subdir.path] = files_count;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
#include "directory.h"
|
#include "collectiondirectory.h"
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
|
|
||||||
class QThread;
|
class QThread;
|
||||||
@@ -74,8 +74,8 @@ class CollectionWatcher : public QObject {
|
|||||||
void SongsDeleted(SongList);
|
void SongsDeleted(SongList);
|
||||||
void SongsUnavailable(SongList songs, bool unavailable = true);
|
void SongsUnavailable(SongList songs, bool unavailable = true);
|
||||||
void SongsReadded(SongList songs, bool unavailable = false);
|
void SongsReadded(SongList songs, bool unavailable = false);
|
||||||
void SubdirsDiscovered(SubdirectoryList subdirs);
|
void SubdirsDiscovered(CollectionSubdirectoryList subdirs);
|
||||||
void SubdirsMTimeUpdated(SubdirectoryList subdirs);
|
void SubdirsMTimeUpdated(CollectionSubdirectoryList subdirs);
|
||||||
void CompilationsNeedUpdating();
|
void CompilationsNeedUpdating();
|
||||||
void UpdateLastSeen(int directory_id, int expire_unavailable_songs_days);
|
void UpdateLastSeen(int directory_id, int expire_unavailable_songs_days);
|
||||||
void ExitFinished();
|
void ExitFinished();
|
||||||
@@ -83,8 +83,8 @@ class CollectionWatcher : public QObject {
|
|||||||
void ScanStarted(int task_id);
|
void ScanStarted(int task_id);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void AddDirectory(const Directory &dir, const SubdirectoryList &subdirs);
|
void AddDirectory(const CollectionDirectory &dir, const CollectionSubdirectoryList &subdirs);
|
||||||
void RemoveDirectory(const Directory &dir);
|
void RemoveDirectory(const CollectionDirectory &dir);
|
||||||
void SetRescanPaused(bool pause);
|
void SetRescanPaused(bool pause);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -102,9 +102,9 @@ class CollectionWatcher : public QObject {
|
|||||||
SongList FindSongsInSubdirectory(const QString &path);
|
SongList FindSongsInSubdirectory(const QString &path);
|
||||||
bool HasSongsWithMissingFingerprint(const QString &path);
|
bool HasSongsWithMissingFingerprint(const QString &path);
|
||||||
bool HasSeenSubdir(const QString &path);
|
bool HasSeenSubdir(const QString &path);
|
||||||
void SetKnownSubdirs(const SubdirectoryList &subdirs);
|
void SetKnownSubdirs(const CollectionSubdirectoryList &subdirs);
|
||||||
SubdirectoryList GetImmediateSubdirs(const QString &path);
|
CollectionSubdirectoryList GetImmediateSubdirs(const QString &path);
|
||||||
SubdirectoryList GetAllSubdirs();
|
CollectionSubdirectoryList GetAllSubdirs();
|
||||||
|
|
||||||
void AddToProgress(const quint64 n = 1);
|
void AddToProgress(const quint64 n = 1);
|
||||||
void AddToProgressMax(const quint64 n);
|
void AddToProgressMax(const quint64 n);
|
||||||
@@ -120,9 +120,9 @@ class CollectionWatcher : public QObject {
|
|||||||
SongList readded_songs;
|
SongList readded_songs;
|
||||||
SongList new_songs;
|
SongList new_songs;
|
||||||
SongList touched_songs;
|
SongList touched_songs;
|
||||||
SubdirectoryList new_subdirs;
|
CollectionSubdirectoryList new_subdirs;
|
||||||
SubdirectoryList touched_subdirs;
|
CollectionSubdirectoryList touched_subdirs;
|
||||||
SubdirectoryList deleted_subdirs;
|
CollectionSubdirectoryList deleted_subdirs;
|
||||||
|
|
||||||
QStringList files_changed_path_;
|
QStringList files_changed_path_;
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ class CollectionWatcher : public QObject {
|
|||||||
QMultiMap<QString, Song> cached_songs_missing_fingerprint_;
|
QMultiMap<QString, Song> cached_songs_missing_fingerprint_;
|
||||||
bool cached_songs_missing_fingerprint_dirty_;
|
bool cached_songs_missing_fingerprint_dirty_;
|
||||||
|
|
||||||
SubdirectoryList known_subdirs_;
|
CollectionSubdirectoryList known_subdirs_;
|
||||||
bool known_subdirs_dirty_;
|
bool known_subdirs_dirty_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -168,7 +168,7 @@ class CollectionWatcher : public QObject {
|
|||||||
void FullScanNow();
|
void FullScanNow();
|
||||||
void RescanTracksNow();
|
void RescanTracksNow();
|
||||||
void RescanPathsNow();
|
void RescanPathsNow();
|
||||||
void ScanSubdirectory(const QString &path, const Subdirectory &subdir, const quint64 files_count, CollectionWatcher::ScanTransaction *t, const bool force_noincremental = false);
|
void ScanSubdirectory(const QString &path, const CollectionSubdirectory &subdir, const quint64 files_count, CollectionWatcher::ScanTransaction *t, const bool force_noincremental = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool FindSongsByPath(const SongList &songs, const QString &path, SongList *out);
|
static bool FindSongsByPath(const SongList &songs, const QString &path, SongList *out);
|
||||||
@@ -179,8 +179,8 @@ class CollectionWatcher : public QObject {
|
|||||||
inline static QString DirectoryPart(const QString &fileName);
|
inline static QString DirectoryPart(const QString &fileName);
|
||||||
QString PickBestImage(const QStringList &images);
|
QString PickBestImage(const QStringList &images);
|
||||||
QUrl ImageForSong(const QString &path, QMap<QString, QStringList> &album_art);
|
QUrl ImageForSong(const QString &path, QMap<QString, QStringList> &album_art);
|
||||||
void AddWatch(const Directory &dir, const QString &path);
|
void AddWatch(const CollectionDirectory &dir, const QString &path);
|
||||||
void RemoveWatch(const Directory &dir, const Subdirectory &subdir);
|
void RemoveWatch(const CollectionDirectory &dir, const CollectionSubdirectory &subdir);
|
||||||
static quint64 GetMtimeForCue(const QString &cue_path);
|
static quint64 GetMtimeForCue(const QString &cue_path);
|
||||||
void PerformScan(const bool incremental, const bool ignore_mtimes);
|
void PerformScan(const bool incremental, const bool ignore_mtimes);
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ class CollectionWatcher : public QObject {
|
|||||||
static void AddChangedSong(const QString &file, const Song &matching_song, const Song &new_song, ScanTransaction *t);
|
static void AddChangedSong(const QString &file, const Song &matching_song, const Song &new_song, ScanTransaction *t);
|
||||||
|
|
||||||
quint64 FilesCountForPath(ScanTransaction *t, const QString &path);
|
quint64 FilesCountForPath(ScanTransaction *t, const QString &path);
|
||||||
quint64 FilesCountForSubdirs(ScanTransaction *t, const SubdirectoryList &subdirs, QMap<QString, quint64> &subdir_files_count);
|
quint64 FilesCountForSubdirs(ScanTransaction *t, const CollectionSubdirectoryList &subdirs, QMap<QString, quint64> &subdir_files_count);
|
||||||
|
|
||||||
QString FindCueFilename(const QString &filename);
|
QString FindCueFilename(const QString &filename);
|
||||||
|
|
||||||
@@ -207,7 +207,7 @@ class CollectionWatcher : public QObject {
|
|||||||
|
|
||||||
FileSystemWatcherInterface *fs_watcher_;
|
FileSystemWatcherInterface *fs_watcher_;
|
||||||
QThread *original_thread_;
|
QThread *original_thread_;
|
||||||
QHash<QString, Directory> subdir_mapping_;
|
QHash<QString, CollectionDirectory> subdir_mapping_;
|
||||||
|
|
||||||
// A list of words use to try to identify the (likely) best image found in an directory to use as cover artwork.
|
// A list of words use to try to identify the (likely) best image found in an directory to use as cover artwork.
|
||||||
// e.g. using ["front", "cover"] would identify front.jpg and exclude back.jpg.
|
// e.g. using ["front", "cover"] would identify front.jpg and exclude back.jpg.
|
||||||
@@ -218,13 +218,14 @@ class CollectionWatcher : public QObject {
|
|||||||
bool song_tracking_;
|
bool song_tracking_;
|
||||||
bool mark_songs_unavailable_;
|
bool mark_songs_unavailable_;
|
||||||
int expire_unavailable_songs_days_;
|
int expire_unavailable_songs_days_;
|
||||||
|
bool overwrite_playcount_;
|
||||||
bool overwrite_rating_;
|
bool overwrite_rating_;
|
||||||
|
|
||||||
bool stop_requested_;
|
bool stop_requested_;
|
||||||
bool abort_requested_;
|
bool abort_requested_;
|
||||||
bool rescan_in_progress_; // True if RescanTracksNow() has been called and is working.
|
bool rescan_in_progress_; // True if RescanTracksNow() has been called and is working.
|
||||||
|
|
||||||
QMap<int, Directory> watched_dirs_;
|
QMap<int, CollectionDirectory> watched_dirs_;
|
||||||
QTimer *rescan_timer_;
|
QTimer *rescan_timer_;
|
||||||
QTimer *periodic_scan_timer_;
|
QTimer *periodic_scan_timer_;
|
||||||
QMap<int, QStringList> rescan_queue_; // dir id -> list of subdirs to be scanned
|
QMap<int, QStringList> rescan_queue_; // dir id -> list of subdirs to be scanned
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This file was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
*
|
|
||||||
* Strawberry 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.
|
|
||||||
*
|
|
||||||
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DIRECTORY_H
|
|
||||||
#define DIRECTORY_H
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <QMetaType>
|
|
||||||
#include <QList>
|
|
||||||
#include <QString>
|
|
||||||
#include <QSqlQuery>
|
|
||||||
|
|
||||||
struct Directory {
|
|
||||||
Directory() : id(-1) {}
|
|
||||||
|
|
||||||
bool operator==(const Directory &other) const {
|
|
||||||
return path == other.path && id == other.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString path;
|
|
||||||
int id;
|
|
||||||
};
|
|
||||||
Q_DECLARE_METATYPE(Directory)
|
|
||||||
|
|
||||||
typedef QList<Directory> DirectoryList;
|
|
||||||
Q_DECLARE_METATYPE(DirectoryList)
|
|
||||||
|
|
||||||
|
|
||||||
struct Subdirectory {
|
|
||||||
Subdirectory() : directory_id(-1), mtime(0) {}
|
|
||||||
|
|
||||||
int directory_id;
|
|
||||||
QString path;
|
|
||||||
qint64 mtime;
|
|
||||||
};
|
|
||||||
Q_DECLARE_METATYPE(Subdirectory)
|
|
||||||
|
|
||||||
typedef QList<Subdirectory> SubdirectoryList;
|
|
||||||
Q_DECLARE_METATYPE(SubdirectoryList)
|
|
||||||
|
|
||||||
#endif // DIRECTORY_H
|
|
||||||
|
|
||||||
|
|||||||
@@ -63,11 +63,7 @@ struct tag_group_by {};
|
|||||||
|
|
||||||
class GroupByDialogPrivate {
|
class GroupByDialogPrivate {
|
||||||
private:
|
private:
|
||||||
typedef multi_index_container<
|
using MappingContainer = multi_index_container<Mapping, indexed_by<ordered_unique<tag<tag_index>, member<Mapping, int, &Mapping::combo_box_index>>, ordered_unique<tag<tag_group_by>, member<Mapping, CollectionModel::GroupBy, &Mapping::group_by>>>>;
|
||||||
Mapping,
|
|
||||||
indexed_by<
|
|
||||||
ordered_unique<tag<tag_index>, member<Mapping, int, &Mapping::combo_box_index> >,
|
|
||||||
ordered_unique<tag<tag_group_by>, member<Mapping, CollectionModel::GroupBy, &Mapping::group_by> > > > MappingContainer;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MappingContainer mapping_;
|
MappingContainer mapping_;
|
||||||
@@ -108,22 +104,31 @@ GroupByDialog::GroupByDialog(QWidget *parent) : QDialog(parent), ui_(new Ui_Grou
|
|||||||
GroupByDialog::~GroupByDialog() = default;
|
GroupByDialog::~GroupByDialog() = default;
|
||||||
|
|
||||||
void GroupByDialog::Reset() {
|
void GroupByDialog::Reset() {
|
||||||
|
|
||||||
ui_->combobox_first->setCurrentIndex(2); // Album Artist
|
ui_->combobox_first->setCurrentIndex(2); // Album Artist
|
||||||
ui_->combobox_second->setCurrentIndex(3); // Album
|
ui_->combobox_second->setCurrentIndex(4); // Album Disc
|
||||||
ui_->combobox_third->setCurrentIndex(0); // None
|
ui_->combobox_third->setCurrentIndex(0); // None
|
||||||
|
ui_->checkbox_separate_albums_by_grouping->setChecked(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupByDialog::accept() {
|
void GroupByDialog::accept() {
|
||||||
|
|
||||||
emit Accepted(CollectionModel::Grouping(
|
emit Accepted(CollectionModel::Grouping(
|
||||||
p_->mapping_.get<tag_index>().find(ui_->combobox_first->currentIndex())->group_by,
|
p_->mapping_.get<tag_index>().find(ui_->combobox_first->currentIndex())->group_by,
|
||||||
p_->mapping_.get<tag_index>().find(ui_->combobox_second->currentIndex())->group_by,
|
p_->mapping_.get<tag_index>().find(ui_->combobox_second->currentIndex())->group_by,
|
||||||
p_->mapping_.get<tag_index>().find(ui_->combobox_third->currentIndex())->group_by)
|
p_->mapping_.get<tag_index>().find(ui_->combobox_third->currentIndex())->group_by),
|
||||||
|
ui_->checkbox_separate_albums_by_grouping->isChecked()
|
||||||
);
|
);
|
||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupByDialog::CollectionGroupingChanged(const CollectionModel::Grouping g) {
|
void GroupByDialog::CollectionGroupingChanged(const CollectionModel::Grouping g, const bool separate_albums_by_grouping) {
|
||||||
|
|
||||||
ui_->combobox_first->setCurrentIndex(p_->mapping_.get<tag_group_by>().find(g[0])->combo_box_index);
|
ui_->combobox_first->setCurrentIndex(p_->mapping_.get<tag_group_by>().find(g[0])->combo_box_index);
|
||||||
ui_->combobox_second->setCurrentIndex(p_->mapping_.get<tag_group_by>().find(g[1])->combo_box_index);
|
ui_->combobox_second->setCurrentIndex(p_->mapping_.get<tag_group_by>().find(g[1])->combo_box_index);
|
||||||
ui_->combobox_third->setCurrentIndex(p_->mapping_.get<tag_group_by>().find(g[2])->combo_box_index);
|
ui_->combobox_third->setCurrentIndex(p_->mapping_.get<tag_group_by>().find(g[2])->combo_box_index);
|
||||||
|
ui_->checkbox_separate_albums_by_grouping->setChecked(separate_albums_by_grouping);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,11 +45,11 @@ class GroupByDialog : public QDialog {
|
|||||||
~GroupByDialog() override;
|
~GroupByDialog() override;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void CollectionGroupingChanged(const CollectionModel::Grouping g);
|
void CollectionGroupingChanged(const CollectionModel::Grouping g, const bool separate_albums_by_grouping);
|
||||||
void accept() override;
|
void accept() override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void Accepted(CollectionModel::Grouping g);
|
void Accepted(CollectionModel::Grouping g, bool separate_albums_by_grouping);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>354</width>
|
<width>394</width>
|
||||||
<height>246</height>
|
<height>273</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -370,6 +370,13 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="checkbox_separate_albums_by_grouping">
|
||||||
|
<property name="text">
|
||||||
|
<string>Separate albums by grouping tag</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="spacer_bottom">
|
<spacer name="spacer_bottom">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2015, Nick Lanham <nick@afternight.org>
|
* Copyright 2015, Nick Lanham <nick@afternight.org>
|
||||||
* Copyright 2019-2021, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2019-2022, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,35 +22,31 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QWidget>
|
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
#include <QItemSelectionModel>
|
#include <QItemSelectionModel>
|
||||||
#include <QAbstractItemModel>
|
|
||||||
#include <QIODevice>
|
|
||||||
#include <QDataStream>
|
|
||||||
#include <QByteArray>
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QVariant>
|
#include <QByteArray>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <QIODevice>
|
||||||
|
#include <QDataStream>
|
||||||
#include <QKeySequence>
|
#include <QKeySequence>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QTreeView>
|
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QtDebug>
|
|
||||||
|
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
#include "core/iconloader.h"
|
#include "core/iconloader.h"
|
||||||
#include "collectionfilterwidget.h"
|
|
||||||
#include "collectionmodel.h"
|
#include "collectionmodel.h"
|
||||||
#include "savedgroupingmanager.h"
|
#include "savedgroupingmanager.h"
|
||||||
#include "ui_savedgroupingmanager.h"
|
#include "ui_savedgroupingmanager.h"
|
||||||
|
|
||||||
SavedGroupingManager::SavedGroupingManager(QWidget *parent)
|
const char *SavedGroupingManager::kSavedGroupingsSettingsGroup = "SavedGroupings";
|
||||||
|
|
||||||
|
SavedGroupingManager::SavedGroupingManager(const QString &saved_groupings_settings_group, QWidget *parent)
|
||||||
: QDialog(parent),
|
: QDialog(parent),
|
||||||
ui_(new Ui_SavedGroupingManager),
|
ui_(new Ui_SavedGroupingManager),
|
||||||
model_(new QStandardItemModel(0, 4, this)),
|
model_(new QStandardItemModel(0, 4, this)),
|
||||||
filter_(nullptr) {
|
saved_groupings_settings_group_(saved_groupings_settings_group) {
|
||||||
|
|
||||||
ui_->setupUi(this);
|
ui_->setupUi(this);
|
||||||
|
|
||||||
@@ -71,7 +67,17 @@ SavedGroupingManager::SavedGroupingManager(QWidget *parent)
|
|||||||
|
|
||||||
SavedGroupingManager::~SavedGroupingManager() {
|
SavedGroupingManager::~SavedGroupingManager() {
|
||||||
delete ui_;
|
delete ui_;
|
||||||
delete model_;
|
}
|
||||||
|
|
||||||
|
QString SavedGroupingManager::GetSavedGroupingsSettingsGroup(const QString &settings_group) {
|
||||||
|
|
||||||
|
if (settings_group.isEmpty() || settings_group == CollectionSettingsPage::kSettingsGroup) {
|
||||||
|
return kSavedGroupingsSettingsGroup;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return QString(kSavedGroupingsSettingsGroup) + "_" + settings_group;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SavedGroupingManager::GroupByToString(const CollectionModel::GroupBy g) {
|
QString SavedGroupingManager::GroupByToString(const CollectionModel::GroupBy g) {
|
||||||
@@ -151,7 +157,7 @@ void SavedGroupingManager::UpdateModel() {
|
|||||||
|
|
||||||
model_->setRowCount(0); // don't use clear, it deletes headers
|
model_->setRowCount(0); // don't use clear, it deletes headers
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(CollectionModel::kSavedGroupingsSettingsGroup);
|
s.beginGroup(saved_groupings_settings_group_);
|
||||||
int version = s.value("version").toInt();
|
int version = s.value("version").toInt();
|
||||||
if (version == 1) {
|
if (version == 1) {
|
||||||
QStringList saved = s.childKeys();
|
QStringList saved = s.childKeys();
|
||||||
@@ -186,7 +192,7 @@ void SavedGroupingManager::Remove() {
|
|||||||
|
|
||||||
if (ui_->list->selectionModel()->hasSelection()) {
|
if (ui_->list->selectionModel()->hasSelection()) {
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(CollectionModel::kSavedGroupingsSettingsGroup);
|
s.beginGroup(saved_groupings_settings_group_);
|
||||||
for (const QModelIndex &idx : ui_->list->selectionModel()->selectedRows()) {
|
for (const QModelIndex &idx : ui_->list->selectionModel()->selectedRows()) {
|
||||||
if (idx.isValid()) {
|
if (idx.isValid()) {
|
||||||
qLog(Debug) << "Remove saved grouping: " << model_->item(idx.row(), 0)->text();
|
qLog(Debug) << "Remove saved grouping: " << model_->item(idx.row(), 0)->text();
|
||||||
@@ -196,7 +202,8 @@ void SavedGroupingManager::Remove() {
|
|||||||
s.endGroup();
|
s.endGroup();
|
||||||
}
|
}
|
||||||
UpdateModel();
|
UpdateModel();
|
||||||
filter_->UpdateGroupByActions();
|
|
||||||
|
emit UpdateGroupByActions();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2015, Nick Lanham <nick@afternight.org>
|
* Copyright 2015, Nick Lanham <nick@afternight.org>
|
||||||
* Copyright 2019-2021, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2019-2022, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -40,14 +40,20 @@ class SavedGroupingManager : public QDialog {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SavedGroupingManager(QWidget *parent = nullptr);
|
explicit SavedGroupingManager(const QString &saved_groupings_settings_group, QWidget *parent = nullptr);
|
||||||
~SavedGroupingManager() override;
|
~SavedGroupingManager() override;
|
||||||
|
|
||||||
|
static const char *kSavedGroupingsSettingsGroup;
|
||||||
|
|
||||||
|
static QString GetSavedGroupingsSettingsGroup(const QString &settings_group);
|
||||||
|
|
||||||
void UpdateModel();
|
void UpdateModel();
|
||||||
void SetFilter(CollectionFilterWidget *filter) { filter_ = filter; }
|
|
||||||
|
|
||||||
static QString GroupByToString(const CollectionModel::GroupBy g);
|
static QString GroupByToString(const CollectionModel::GroupBy g);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void UpdateGroupByActions();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void UpdateButtonState();
|
void UpdateButtonState();
|
||||||
void Remove();
|
void Remove();
|
||||||
@@ -55,7 +61,7 @@ class SavedGroupingManager : public QDialog {
|
|||||||
private:
|
private:
|
||||||
Ui_SavedGroupingManager *ui_;
|
Ui_SavedGroupingManager *ui_;
|
||||||
QStandardItemModel *model_;
|
QStandardItemModel *model_;
|
||||||
CollectionFilterWidget *filter_;
|
QString saved_groupings_settings_group_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SAVEDGROUPINGMANAGER_H
|
#endif // SAVEDGROUPINGMANAGER_H
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
#cmakedefine HAVE_MUSICBRAINZ
|
#cmakedefine HAVE_MUSICBRAINZ
|
||||||
#cmakedefine HAVE_GLOBALSHORTCUTS
|
#cmakedefine HAVE_GLOBALSHORTCUTS
|
||||||
#cmakedefine HAVE_X11_GLOBALSHORTCUTS
|
#cmakedefine HAVE_X11_GLOBALSHORTCUTS
|
||||||
|
#cmakedefine HAVE_ICU
|
||||||
|
|
||||||
#cmakedefine USE_INSTALL_PREFIX
|
#cmakedefine USE_INSTALL_PREFIX
|
||||||
|
|
||||||
#cmakedefine HAVE_GSTREAMER
|
#cmakedefine HAVE_GSTREAMER
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2020-2021, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2020-2022, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -37,13 +37,13 @@
|
|||||||
#include <QContextMenuEvent>
|
#include <QContextMenuEvent>
|
||||||
#include <QPaintEvent>
|
#include <QPaintEvent>
|
||||||
|
|
||||||
#include "core/imageutils.h"
|
#include "utilities/imageutils.h"
|
||||||
#include "covermanager/albumcoverchoicecontroller.h"
|
#include "covermanager/albumcoverchoicecontroller.h"
|
||||||
|
|
||||||
#include "contextview.h"
|
#include "contextview.h"
|
||||||
#include "contextalbum.h"
|
#include "contextalbum.h"
|
||||||
|
|
||||||
const int ContextAlbum::kWidgetSpacing = 40;
|
const int ContextAlbum::kFadeTimeLineMs = 1000;
|
||||||
|
|
||||||
ContextAlbum::ContextAlbum(QWidget *parent)
|
ContextAlbum::ContextAlbum(QWidget *parent)
|
||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
@@ -51,23 +51,26 @@ ContextAlbum::ContextAlbum(QWidget *parent)
|
|||||||
context_view_(nullptr),
|
context_view_(nullptr),
|
||||||
album_cover_choice_controller_(nullptr),
|
album_cover_choice_controller_(nullptr),
|
||||||
downloading_covers_(false),
|
downloading_covers_(false),
|
||||||
timeline_fade_(new QTimeLine(1000, this)),
|
timeline_fade_(new QTimeLine(kFadeTimeLineMs, this)),
|
||||||
image_strawberry_(":/pictures/strawberry.png"),
|
image_strawberry_(":/pictures/strawberry.png"),
|
||||||
image_original_(image_strawberry_),
|
image_original_(image_strawberry_),
|
||||||
pixmap_previous_opacity_(0),
|
pixmap_current_opacity_(1.0) {
|
||||||
prev_width_(width()) {
|
|
||||||
|
|
||||||
setObjectName("context-widget-album");
|
setObjectName("context-widget-album");
|
||||||
|
|
||||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
|
||||||
cover_loader_options_.desired_height_ = 600;
|
cover_loader_options_.desired_height_ = width();
|
||||||
cover_loader_options_.pad_output_image_ = true;
|
cover_loader_options_.pad_output_image_ = true;
|
||||||
cover_loader_options_.scale_output_image_ = true;
|
cover_loader_options_.scale_output_image_ = true;
|
||||||
QImage image = ImageUtils::ScaleAndPad(image_strawberry_, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
|
QImage image = ImageUtils::ScaleAndPad(image_strawberry_, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
|
||||||
if (!image.isNull()) pixmap_current_ = QPixmap::fromImage(image);
|
if (!image.isNull()) {
|
||||||
|
pixmap_current_ = QPixmap::fromImage(image);
|
||||||
|
}
|
||||||
|
|
||||||
QObject::connect(timeline_fade_, &QTimeLine::valueChanged, this, &ContextAlbum::FadePreviousTrack);
|
timeline_fade_->setDirection(QTimeLine::Forward);
|
||||||
timeline_fade_->setDirection(QTimeLine::Backward); // 1.0 -> 0.0
|
QObject::connect(timeline_fade_, &QTimeLine::valueChanged, this, &ContextAlbum::FadeCurrentCover);
|
||||||
|
QObject::connect(timeline_fade_, &QTimeLine::finished, this, &ContextAlbum::FadeCurrentCoverFinished);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,8 +89,21 @@ void ContextAlbum::Init(ContextView *context_view, AlbumCoverChoiceController *a
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextAlbum::contextMenuEvent(QContextMenuEvent *e) {
|
QSize ContextAlbum::sizeHint() const {
|
||||||
if (menu_ && image_original_ != image_strawberry_) menu_->popup(mapToGlobal(e->pos()));
|
|
||||||
|
return QSize(pixmap_current_.width(), pixmap_current_.height());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::paintEvent(QPaintEvent*) {
|
||||||
|
|
||||||
|
QPainter p(this);
|
||||||
|
p.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||||
|
DrawPreviousCovers(&p);
|
||||||
|
DrawImage(&p, pixmap_current_, pixmap_current_opacity_);
|
||||||
|
DrawSpinner(&p);
|
||||||
|
p.end();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextAlbum::mouseDoubleClickEvent(QMouseEvent *e) {
|
void ContextAlbum::mouseDoubleClickEvent(QMouseEvent *e) {
|
||||||
@@ -99,93 +115,146 @@ void ContextAlbum::mouseDoubleClickEvent(QMouseEvent *e) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextAlbum::paintEvent(QPaintEvent*) {
|
void ContextAlbum::contextMenuEvent(QContextMenuEvent *e) {
|
||||||
|
|
||||||
QPainter p(this);
|
if (menu_ && image_original_ != image_strawberry_) {
|
||||||
|
menu_->popup(mapToGlobal(e->pos()));
|
||||||
DrawImage(&p);
|
}
|
||||||
|
else {
|
||||||
// Draw the previous track's image if we're fading
|
QWidget::contextMenuEvent(e);
|
||||||
if (!pixmap_previous_.isNull()) {
|
|
||||||
p.setOpacity(pixmap_previous_opacity_);
|
|
||||||
p.drawPixmap(0, 0, pixmap_previous_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextAlbum::DrawImage(QPainter *p) {
|
void ContextAlbum::UpdateWidth(const int new_width) {
|
||||||
|
|
||||||
p->setRenderHint(QPainter::SmoothPixmapTransform);
|
|
||||||
|
|
||||||
if (width() != prev_width_) {
|
if (new_width != cover_loader_options_.desired_height_) {
|
||||||
cover_loader_options_.desired_height_ = width() - kWidgetSpacing;
|
cover_loader_options_.desired_height_ = new_width;
|
||||||
QImage image = ImageUtils::ScaleAndPad(image_original_, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
|
ScaleCover();
|
||||||
if (image.isNull()) pixmap_current_ = QPixmap();
|
ScalePreviousCovers();
|
||||||
else pixmap_current_ = QPixmap::fromImage(image);
|
updateGeometry();
|
||||||
prev_width_ = width();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p->drawPixmap(0, 0, width() - kWidgetSpacing, width() - kWidgetSpacing, pixmap_current_);
|
|
||||||
if (downloading_covers_ && spinner_animation_) {
|
|
||||||
p->drawPixmap(50, 50, 16, 16, spinner_animation_->currentPixmap());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbum::FadePreviousTrack(const qreal value) {
|
|
||||||
|
|
||||||
pixmap_previous_opacity_ = value;
|
|
||||||
if (qFuzzyCompare(pixmap_previous_opacity_, qreal(0.0))) {
|
|
||||||
image_previous_ = QImage();
|
|
||||||
pixmap_previous_ = QPixmap();
|
|
||||||
}
|
|
||||||
update();
|
|
||||||
|
|
||||||
if (value == 0 && image_original_ == image_strawberry_) {
|
|
||||||
emit FadeStopFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbum::ScaleCover() {
|
|
||||||
|
|
||||||
cover_loader_options_.desired_height_ = width() - kWidgetSpacing;
|
|
||||||
QImage image = ImageUtils::ScaleAndPad(image_original_, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
|
|
||||||
if (image.isNull()) pixmap_current_ = QPixmap();
|
|
||||||
else pixmap_current_ = QPixmap::fromImage(image);
|
|
||||||
prev_width_ = width();
|
|
||||||
update();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextAlbum::SetImage(QImage image) {
|
void ContextAlbum::SetImage(QImage image) {
|
||||||
|
|
||||||
if (image.isNull()) image = image_strawberry_;
|
if (image.isNull()) {
|
||||||
|
image = image_strawberry_;
|
||||||
|
}
|
||||||
|
|
||||||
if (downloading_covers_) {
|
if (downloading_covers_) {
|
||||||
downloading_covers_ = false;
|
downloading_covers_ = false;
|
||||||
spinner_animation_.reset();
|
spinner_animation_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache the current pixmap so we can fade between them
|
QImage image_previous = image_original_;
|
||||||
pixmap_previous_ = QPixmap(width() - kWidgetSpacing, width() - kWidgetSpacing);
|
QPixmap pixmap_previous = pixmap_current_;
|
||||||
pixmap_previous_.fill(palette().window().color());
|
qreal opacity_previous = pixmap_current_opacity_;
|
||||||
pixmap_previous_opacity_ = 1.0;
|
|
||||||
|
|
||||||
QPainter p(&pixmap_previous_);
|
|
||||||
DrawImage(&p);
|
|
||||||
p.end();
|
|
||||||
|
|
||||||
image_previous_ = image_original_;
|
|
||||||
image_original_ = image;
|
image_original_ = image;
|
||||||
|
pixmap_current_opacity_ = 0.0;
|
||||||
ScaleCover();
|
ScaleCover();
|
||||||
|
|
||||||
// Were we waiting for this cover to load before we started fading?
|
if (!pixmap_previous.isNull()) {
|
||||||
if (!pixmap_previous_.isNull() && timeline_fade_) {
|
std::shared_ptr<PreviousCover> previous_cover = std::make_shared<PreviousCover>();
|
||||||
|
previous_cover->image = image_previous;
|
||||||
|
previous_cover->pixmap = pixmap_previous;
|
||||||
|
previous_cover->opacity = opacity_previous;
|
||||||
|
previous_cover->timeline.reset(new QTimeLine(kFadeTimeLineMs), [](QTimeLine *timeline) { timeline->deleteLater(); });
|
||||||
|
previous_cover->timeline->setDirection(QTimeLine::Backward);
|
||||||
|
previous_cover->timeline->setCurrentTime(timeline_fade_->state() == QTimeLine::Running ? timeline_fade_->currentTime() : kFadeTimeLineMs);
|
||||||
|
QObject::connect(previous_cover->timeline.get(), &QTimeLine::valueChanged, this, [this, previous_cover]() { FadePreviousCover(previous_cover); });
|
||||||
|
QObject::connect(previous_cover->timeline.get(), &QTimeLine::finished, this, [this, previous_cover]() { FadePreviousCoverFinished(previous_cover); });
|
||||||
|
previous_covers_ << previous_cover;
|
||||||
|
previous_cover->timeline->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeline_fade_->state() == QTimeLine::Running) {
|
||||||
timeline_fade_->stop();
|
timeline_fade_->stop();
|
||||||
timeline_fade_->setDirection(QTimeLine::Backward); // 1.0 -> 0.0
|
}
|
||||||
timeline_fade_->start();
|
timeline_fade_->start();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::DrawImage(QPainter *p, const QPixmap &pixmap, const qreal opacity) {
|
||||||
|
|
||||||
|
if (qFuzzyCompare(opacity, static_cast<qreal>(0.0))) return;
|
||||||
|
|
||||||
|
p->setOpacity(opacity);
|
||||||
|
p->drawPixmap(0, 0, pixmap.width(), pixmap.height(), pixmap);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::DrawSpinner(QPainter *p) {
|
||||||
|
|
||||||
|
if (downloading_covers_) {
|
||||||
|
p->drawPixmap(50, 50, 16, 16, spinner_animation_->currentPixmap());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::DrawPreviousCovers(QPainter *p) {
|
||||||
|
|
||||||
|
for (std::shared_ptr<PreviousCover> previous_cover : previous_covers_) {
|
||||||
|
DrawImage(p, previous_cover->pixmap, previous_cover->opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::FadeCurrentCover(const qreal value) {
|
||||||
|
|
||||||
|
if (value <= pixmap_current_opacity_) return;
|
||||||
|
|
||||||
|
pixmap_current_opacity_ = value;
|
||||||
|
update();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::FadeCurrentCoverFinished() {
|
||||||
|
|
||||||
|
if (image_original_ == image_strawberry_) {
|
||||||
|
emit FadeStopFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::FadePreviousCover(std::shared_ptr<PreviousCover> previous_cover) {
|
||||||
|
|
||||||
|
if (previous_cover->timeline->currentValue() >= previous_cover->opacity) return;
|
||||||
|
|
||||||
|
previous_cover->opacity = previous_cover->timeline->currentValue();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::FadePreviousCoverFinished(std::shared_ptr<PreviousCover> previous_cover) {
|
||||||
|
|
||||||
|
previous_covers_.removeAll(previous_cover);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::ScaleCover() {
|
||||||
|
|
||||||
|
QImage image = ImageUtils::ScaleAndPad(image_original_, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
|
||||||
|
if (image.isNull()) {
|
||||||
|
pixmap_current_ = QPixmap();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pixmap_current_ = QPixmap::fromImage(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::ScalePreviousCovers() {
|
||||||
|
|
||||||
|
for (std::shared_ptr<PreviousCover> previous_cover : previous_covers_) {
|
||||||
|
QImage image = ImageUtils::ScaleAndPad(previous_cover->image, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
|
||||||
|
if (image.isNull()) {
|
||||||
|
previous_cover->pixmap = QPixmap();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
previous_cover->pixmap = QPixmap::fromImage(image);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2020-2021, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2020-2022, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QList>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
@@ -50,15 +51,31 @@ class ContextAlbum : public QWidget {
|
|||||||
|
|
||||||
void Init(ContextView *context_view, AlbumCoverChoiceController *album_cover_choice_controller);
|
void Init(ContextView *context_view, AlbumCoverChoiceController *album_cover_choice_controller);
|
||||||
void SetImage(QImage image = QImage());
|
void SetImage(QImage image = QImage());
|
||||||
|
void UpdateWidth(const int width);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
QSize sizeHint() const override;
|
||||||
void paintEvent(QPaintEvent*) override;
|
void paintEvent(QPaintEvent*) override;
|
||||||
void contextMenuEvent(QContextMenuEvent *e) override;
|
|
||||||
void mouseDoubleClickEvent(QMouseEvent *e) override;
|
void mouseDoubleClickEvent(QMouseEvent *e) override;
|
||||||
|
void contextMenuEvent(QContextMenuEvent *e) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DrawImage(QPainter *p);
|
|
||||||
|
struct PreviousCover {
|
||||||
|
PreviousCover() : opacity(0.0) {}
|
||||||
|
QImage image;
|
||||||
|
QPixmap pixmap;
|
||||||
|
qreal opacity;
|
||||||
|
std::shared_ptr<QTimeLine> timeline;
|
||||||
|
};
|
||||||
|
|
||||||
|
QList<std::shared_ptr<PreviousCover>> previous_covers_;
|
||||||
|
|
||||||
|
void DrawImage(QPainter *p, const QPixmap &pixmap, const qreal opacity);
|
||||||
|
void DrawSpinner(QPainter *p);
|
||||||
|
void DrawPreviousCovers(QPainter *p);
|
||||||
void ScaleCover();
|
void ScaleCover();
|
||||||
|
void ScalePreviousCovers();
|
||||||
void GetCoverAutomatically();
|
void GetCoverAutomatically();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@@ -67,13 +84,16 @@ class ContextAlbum : public QWidget {
|
|||||||
private slots:
|
private slots:
|
||||||
void Update() { update(); }
|
void Update() { update(); }
|
||||||
void AutomaticCoverSearchDone();
|
void AutomaticCoverSearchDone();
|
||||||
void FadePreviousTrack(const qreal value);
|
void FadeCurrentCover(const qreal value);
|
||||||
|
void FadeCurrentCoverFinished();
|
||||||
|
void FadePreviousCover(std::shared_ptr<PreviousCover> previouscover);
|
||||||
|
void FadePreviousCoverFinished(std::shared_ptr<PreviousCover> previouscover);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void SearchCoverInProgress();
|
void SearchCoverInProgress();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int kWidgetSpacing;
|
static const int kFadeTimeLineMs;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMenu *menu_;
|
QMenu *menu_;
|
||||||
@@ -84,12 +104,9 @@ class ContextAlbum : public QWidget {
|
|||||||
QTimeLine *timeline_fade_;
|
QTimeLine *timeline_fade_;
|
||||||
QImage image_strawberry_;
|
QImage image_strawberry_;
|
||||||
QImage image_original_;
|
QImage image_original_;
|
||||||
QImage image_previous_;
|
|
||||||
QPixmap pixmap_current_;
|
QPixmap pixmap_current_;
|
||||||
QPixmap pixmap_previous_;
|
qreal pixmap_current_opacity_;
|
||||||
qreal pixmap_previous_opacity_;
|
|
||||||
std::unique_ptr<QMovie> spinner_animation_;
|
std::unique_ptr<QMovie> spinner_animation_;
|
||||||
int prev_width_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONTEXTALBUM_H
|
#endif // CONTEXTALBUM_H
|
||||||
|
|||||||
@@ -1,390 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This code was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
|
|
||||||
*
|
|
||||||
* Strawberry 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.
|
|
||||||
*
|
|
||||||
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QMimeData>
|
|
||||||
#include <QMetaType>
|
|
||||||
#include <QVariant>
|
|
||||||
#include <QList>
|
|
||||||
#include <QSet>
|
|
||||||
#include <QRegularExpression>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QImage>
|
|
||||||
#include <QPixmapCache>
|
|
||||||
|
|
||||||
#include "core/application.h"
|
|
||||||
#include "core/database.h"
|
|
||||||
#include "core/iconloader.h"
|
|
||||||
#include "collection/collectionquery.h"
|
|
||||||
#include "collection/collectionbackend.h"
|
|
||||||
#include "collection/collectionmodel.h"
|
|
||||||
#include "collection/collectionitem.h"
|
|
||||||
#include "playlist/playlistmanager.h"
|
|
||||||
#include "playlist/songmimedata.h"
|
|
||||||
#include "covermanager/albumcoverloader.h"
|
|
||||||
#include "covermanager/albumcoverloaderoptions.h"
|
|
||||||
#include "covermanager/albumcoverloaderresult.h"
|
|
||||||
|
|
||||||
#include "contextalbumsmodel.h"
|
|
||||||
|
|
||||||
const int ContextAlbumsModel::kPrettyCoverSize = 32;
|
|
||||||
|
|
||||||
ContextAlbumsModel::ContextAlbumsModel(CollectionBackend *backend, Application *app, QObject *parent)
|
|
||||||
: SimpleTreeModel<CollectionItem>(new CollectionItem(this), parent),
|
|
||||||
backend_(backend),
|
|
||||||
app_(app),
|
|
||||||
album_icon_(IconLoader::Load("cdcase")) {
|
|
||||||
|
|
||||||
root_->lazy_loaded = true;
|
|
||||||
|
|
||||||
cover_loader_options_.get_image_data_ = false;
|
|
||||||
cover_loader_options_.scale_output_image_ = true;
|
|
||||||
cover_loader_options_.pad_output_image_ = true;
|
|
||||||
cover_loader_options_.desired_height_ = kPrettyCoverSize;
|
|
||||||
|
|
||||||
QObject::connect(app_->album_cover_loader(), &AlbumCoverLoader::AlbumCoverLoaded, this, &ContextAlbumsModel::AlbumCoverLoaded);
|
|
||||||
|
|
||||||
QIcon nocover = IconLoader::Load("cdcase");
|
|
||||||
QList<QSize> nocover_sizes = nocover.availableSizes();
|
|
||||||
no_cover_icon_ = nocover.pixmap(nocover_sizes.last()).scaled(kPrettyCoverSize, kPrettyCoverSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ContextAlbumsModel::~ContextAlbumsModel() { delete root_; }
|
|
||||||
|
|
||||||
void ContextAlbumsModel::AddSongs(const SongList &songs) {
|
|
||||||
|
|
||||||
for (const Song &song : songs) {
|
|
||||||
if (song_nodes_.contains(song.id())) continue;
|
|
||||||
QString key = CollectionModel::ContainerKey(CollectionModel::GroupBy_Album, song);
|
|
||||||
CollectionItem *container = nullptr;
|
|
||||||
if (container_nodes_.contains(key)) {
|
|
||||||
container = container_nodes_[key];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
container = ItemFromSong(CollectionItem::Type_Container, true, root_, song, 0);
|
|
||||||
container_nodes_.insert(key, container);
|
|
||||||
}
|
|
||||||
song_nodes_[song.id()] = ItemFromSong(CollectionItem::Type_Song, true, container, song, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ContextAlbumsModel::AlbumIconPixmapCacheKey(const QModelIndex &idx) {
|
|
||||||
|
|
||||||
QStringList path;
|
|
||||||
QModelIndex index_copy(idx);
|
|
||||||
while (index_copy.isValid()) {
|
|
||||||
path.prepend(index_copy.data().toString());
|
|
||||||
index_copy = index_copy.parent();
|
|
||||||
}
|
|
||||||
return "contextalbumsart:" + path.join("/");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ContextAlbumsModel::AlbumIcon(const QModelIndex &idx) {
|
|
||||||
|
|
||||||
CollectionItem *item = IndexToItem(idx);
|
|
||||||
if (!item) return no_cover_icon_;
|
|
||||||
|
|
||||||
// Check the cache for a pixmap we already loaded.
|
|
||||||
const QString cache_key = AlbumIconPixmapCacheKey(idx);
|
|
||||||
|
|
||||||
QPixmap cached_pixmap;
|
|
||||||
if (QPixmapCache::find(cache_key, &cached_pixmap)) {
|
|
||||||
return cached_pixmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maybe we're loading a pixmap already?
|
|
||||||
if (pending_cache_keys_.contains(cache_key)) {
|
|
||||||
return no_cover_icon_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No art is cached and we're not loading it already. Load art for the first song in the album.
|
|
||||||
SongList songs = GetChildSongs(idx);
|
|
||||||
if (!songs.isEmpty()) {
|
|
||||||
const quint64 id = app_->album_cover_loader()->LoadImageAsync(cover_loader_options_, songs.first());
|
|
||||||
pending_art_.insert(id, ItemAndCacheKey(item, cache_key));
|
|
||||||
pending_cache_keys_.insert(cache_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return no_cover_icon_;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsModel::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result) {
|
|
||||||
|
|
||||||
if (!pending_art_.contains(id)) return;
|
|
||||||
|
|
||||||
ItemAndCacheKey item_and_cache_key = pending_art_.take(id);
|
|
||||||
|
|
||||||
CollectionItem *item = item_and_cache_key.first;
|
|
||||||
if (!item) return;
|
|
||||||
|
|
||||||
const QString &cache_key = item_and_cache_key.second;
|
|
||||||
if (pending_cache_keys_.contains(cache_key)) {
|
|
||||||
pending_cache_keys_.remove(cache_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert this image in the cache.
|
|
||||||
if (!result.success || result.image_scaled.isNull() || result.type == AlbumCoverLoaderResult::Type_ManuallyUnset) {
|
|
||||||
// Set the no_cover image so we don't continually try to load art.
|
|
||||||
QPixmapCache::insert(cache_key, no_cover_icon_);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
QPixmap image_pixmap;
|
|
||||||
image_pixmap = QPixmap::fromImage(result.image_scaled);
|
|
||||||
QPixmapCache::insert(cache_key, image_pixmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
const QModelIndex idx = ItemToIndex(item);
|
|
||||||
|
|
||||||
emit dataChanged(idx, idx);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ContextAlbumsModel::data(const QModelIndex &idx, int role) const {
|
|
||||||
|
|
||||||
const CollectionItem *item = IndexToItem(idx);
|
|
||||||
|
|
||||||
if (role == Qt::DecorationRole && item->type == CollectionItem::Type_Container && item->container_level == 0) {
|
|
||||||
return const_cast<ContextAlbumsModel*>(this)->AlbumIcon(idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data(item, role);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ContextAlbumsModel::data(const CollectionItem *item, int role) const {
|
|
||||||
|
|
||||||
switch (role) {
|
|
||||||
case Qt::DisplayRole:
|
|
||||||
case Qt::ToolTipRole:
|
|
||||||
return item->DisplayText();
|
|
||||||
|
|
||||||
case Qt::DecorationRole:
|
|
||||||
switch (item->type) {
|
|
||||||
case CollectionItem::Type_Container:
|
|
||||||
if (item->type == CollectionItem::Type_Container && item->container_level == 0) { return album_icon_; }
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Role_Type:
|
|
||||||
return item->type;
|
|
||||||
|
|
||||||
case Role_ContainerType:
|
|
||||||
return item->type;
|
|
||||||
|
|
||||||
case Role_Key:
|
|
||||||
return item->key;
|
|
||||||
|
|
||||||
case Role_Artist:
|
|
||||||
return item->metadata.artist();
|
|
||||||
|
|
||||||
case Role_Editable:
|
|
||||||
if (item->type == CollectionItem::Type_Container) {
|
|
||||||
// if we have even one non editable item as a child, we ourselves are not available for edit
|
|
||||||
if (!item->children.isEmpty()) {
|
|
||||||
for (CollectionItem *child : item->children) {
|
|
||||||
if (!data(child, role).toBool()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (item->type == CollectionItem::Type_Song) {
|
|
||||||
return item->metadata.IsEditable();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Role_SortText:
|
|
||||||
return item->SortText();
|
|
||||||
|
|
||||||
default:
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsModel::Reset() {
|
|
||||||
|
|
||||||
for (QMap<QString, CollectionItem*>::const_iterator it = container_nodes_.constBegin(); it != container_nodes_.constEnd(); ++it) {
|
|
||||||
const QString cache_key = AlbumIconPixmapCacheKey(ItemToIndex(it.value()));
|
|
||||||
QPixmapCache::remove(cache_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
beginResetModel();
|
|
||||||
delete root_;
|
|
||||||
song_nodes_.clear();
|
|
||||||
container_nodes_.clear();
|
|
||||||
pending_art_.clear();
|
|
||||||
pending_cache_keys_.clear();
|
|
||||||
|
|
||||||
root_ = new CollectionItem(this);
|
|
||||||
root_->lazy_loaded = true;
|
|
||||||
endResetModel();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionItem *ContextAlbumsModel::ItemFromSong(CollectionItem::Type item_type, const bool signal, CollectionItem *parent, const Song &s, const int container_level) {
|
|
||||||
|
|
||||||
if (signal) beginInsertRows(ItemToIndex(parent), static_cast<int>(parent->children.count()), static_cast<int>(parent->children.count()));
|
|
||||||
|
|
||||||
CollectionItem *item = new CollectionItem(item_type, parent);
|
|
||||||
item->container_level = container_level;
|
|
||||||
item->lazy_loaded = true;
|
|
||||||
|
|
||||||
if (item_type == CollectionItem::Type_Container) {
|
|
||||||
item->key = CollectionModel::ContainerKey(CollectionModel::GroupBy_Album, s);
|
|
||||||
item->display_text = CollectionModel::TextOrUnknown(s.album());
|
|
||||||
item->sort_text = CollectionModel::SortTextForArtist(s.album());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
item->key = s.album() + " " + s.title();
|
|
||||||
item->display_text = CollectionModel::TextOrUnknown(s.title());
|
|
||||||
item->sort_text = CollectionModel::SortTextForSong(s);
|
|
||||||
item->metadata = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signal) endInsertRows();
|
|
||||||
|
|
||||||
return item;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Qt::ItemFlags ContextAlbumsModel::flags(const QModelIndex &idx) const {
|
|
||||||
|
|
||||||
switch (IndexToItem(idx)->type) {
|
|
||||||
case CollectionItem::Type_Song:
|
|
||||||
case CollectionItem::Type_Container:
|
|
||||||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled;
|
|
||||||
case CollectionItem::Type_Root:
|
|
||||||
case CollectionItem::Type_LoadingIndicator:
|
|
||||||
default:
|
|
||||||
return Qt::ItemIsEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList ContextAlbumsModel::mimeTypes() const {
|
|
||||||
return QStringList() << "text/uri-list";
|
|
||||||
}
|
|
||||||
|
|
||||||
QMimeData *ContextAlbumsModel::mimeData(const QModelIndexList &indexes) const {
|
|
||||||
|
|
||||||
if (indexes.isEmpty()) return nullptr;
|
|
||||||
|
|
||||||
SongMimeData *data = new SongMimeData;
|
|
||||||
QList<QUrl> urls;
|
|
||||||
QSet<int> song_ids;
|
|
||||||
|
|
||||||
data->backend = backend_;
|
|
||||||
|
|
||||||
for (const QModelIndex &idx : indexes) {
|
|
||||||
GetChildSongs(IndexToItem(idx), &urls, &data->songs, &song_ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
data->setUrls(urls);
|
|
||||||
data->name_for_new_playlist_ = PlaylistManager::GetNameForNewPlaylist(data->songs);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ContextAlbumsModel::CompareItems(const CollectionItem *a, const CollectionItem *b) const {
|
|
||||||
|
|
||||||
QVariant left(data(a, ContextAlbumsModel::Role_SortText));
|
|
||||||
QVariant right(data(b, ContextAlbumsModel::Role_SortText));
|
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
if (left.metaType().id() == QMetaType::Int)
|
|
||||||
#else
|
|
||||||
if (left.type() == QVariant::Int)
|
|
||||||
#endif
|
|
||||||
return left.toInt() < right.toInt();
|
|
||||||
else return left.toString() < right.toString();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsModel::GetChildSongs(CollectionItem *item, QList<QUrl> *urls, SongList *songs, QSet<int> *song_ids) const {
|
|
||||||
|
|
||||||
switch (item->type) {
|
|
||||||
case CollectionItem::Type_Container:{
|
|
||||||
|
|
||||||
QList<CollectionItem*> children = item->children;
|
|
||||||
std::sort(children.begin(), children.end(), std::bind(&ContextAlbumsModel::CompareItems, this, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
|
|
||||||
for (CollectionItem *child : children) {
|
|
||||||
GetChildSongs(child, urls, songs, song_ids);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case CollectionItem::Type_Song:
|
|
||||||
urls->append(item->metadata.url());
|
|
||||||
if (!song_ids->contains(item->metadata.id())) {
|
|
||||||
songs->append(item->metadata);
|
|
||||||
song_ids->insert(item->metadata.id());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SongList ContextAlbumsModel::GetChildSongs(const QModelIndexList &indexes) const {
|
|
||||||
|
|
||||||
QList<QUrl> dontcare;
|
|
||||||
SongList ret;
|
|
||||||
QSet<int> song_ids;
|
|
||||||
|
|
||||||
for (const QModelIndex &idx : indexes) {
|
|
||||||
GetChildSongs(IndexToItem(idx), &dontcare, &ret, &song_ids);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SongList ContextAlbumsModel::GetChildSongs(const QModelIndex &idx) const {
|
|
||||||
return GetChildSongs(QModelIndexList() << idx);
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This code was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
|
|
||||||
*
|
|
||||||
* Strawberry 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.
|
|
||||||
*
|
|
||||||
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CONTEXTALBUMSMODEL_H
|
|
||||||
#define CONTEXTALBUMSMODEL_H
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QAbstractItemModel>
|
|
||||||
#include <QPair>
|
|
||||||
#include <QSet>
|
|
||||||
#include <QList>
|
|
||||||
#include <QMap>
|
|
||||||
#include <QVariant>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QImage>
|
|
||||||
#include <QPixmap>
|
|
||||||
#include <QIcon>
|
|
||||||
|
|
||||||
#include "core/simpletreemodel.h"
|
|
||||||
#include "core/song.h"
|
|
||||||
#include "collection/collectionquery.h"
|
|
||||||
#include "collection/collectionitem.h"
|
|
||||||
#include "covermanager/albumcoverloaderoptions.h"
|
|
||||||
#include "covermanager/albumcoverloaderresult.h"
|
|
||||||
|
|
||||||
class QMimeData;
|
|
||||||
|
|
||||||
class Application;
|
|
||||||
class CollectionBackend;
|
|
||||||
class CollectionItem;
|
|
||||||
|
|
||||||
class ContextAlbumsModel : public SimpleTreeModel<CollectionItem> {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ContextAlbumsModel(CollectionBackend *backend, Application *app, QObject *parent = nullptr);
|
|
||||||
~ContextAlbumsModel() override;
|
|
||||||
|
|
||||||
static const int kPrettyCoverSize;
|
|
||||||
|
|
||||||
enum Role {
|
|
||||||
Role_Type = Qt::UserRole + 1,
|
|
||||||
Role_ContainerType,
|
|
||||||
Role_SortText,
|
|
||||||
Role_Key,
|
|
||||||
Role_Artist,
|
|
||||||
Role_Editable,
|
|
||||||
LastRole
|
|
||||||
};
|
|
||||||
|
|
||||||
void GetChildSongs(CollectionItem *item, QList<QUrl> *urls, SongList *songs, QSet<int> *song_ids) const;
|
|
||||||
SongList GetChildSongs(const QModelIndex &idx) const;
|
|
||||||
SongList GetChildSongs(const QModelIndexList &indexes) const;
|
|
||||||
|
|
||||||
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
|
||||||
Qt::ItemFlags flags(const QModelIndex &idx) const override;
|
|
||||||
QStringList mimeTypes() const override;
|
|
||||||
QMimeData *mimeData(const QModelIndexList &indexes) const override;
|
|
||||||
|
|
||||||
void Reset();
|
|
||||||
void AddSongs(const SongList &songs);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result);
|
|
||||||
|
|
||||||
private:
|
|
||||||
CollectionItem *ItemFromSong(CollectionItem::Type item_type, const bool signal, CollectionItem *parent, const Song &s, const int container_level);
|
|
||||||
|
|
||||||
static QString AlbumIconPixmapCacheKey(const QModelIndex &idx);
|
|
||||||
QVariant AlbumIcon(const QModelIndex &idx);
|
|
||||||
QVariant data(const CollectionItem *item, int role) const;
|
|
||||||
bool CompareItems(const CollectionItem *a, const CollectionItem *b) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
CollectionBackend *backend_;
|
|
||||||
Application *app_;
|
|
||||||
QueryOptions query_options_;
|
|
||||||
QMap<QString, CollectionItem*> container_nodes_;
|
|
||||||
QMap<int, CollectionItem*> song_nodes_;
|
|
||||||
QIcon album_icon_;
|
|
||||||
QPixmap no_cover_icon_;
|
|
||||||
AlbumCoverLoaderOptions cover_loader_options_;
|
|
||||||
typedef QPair<CollectionItem*, QString> ItemAndCacheKey;
|
|
||||||
QMap<quint64, ItemAndCacheKey> pending_art_;
|
|
||||||
QSet<QString> pending_cache_keys_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CONTEXTALBUMSMODEL_H
|
|
||||||
@@ -1,434 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This code was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
|
|
||||||
*
|
|
||||||
* Strawberry 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.
|
|
||||||
*
|
|
||||||
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <qcoreevent.h>
|
|
||||||
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QTreeView>
|
|
||||||
#include <QItemSelectionModel>
|
|
||||||
#include <QSortFilterProxyModel>
|
|
||||||
#include <QAbstractItemView>
|
|
||||||
#include <QStyleOptionViewItem>
|
|
||||||
#include <QAbstractScrollArea>
|
|
||||||
#include <QMimeData>
|
|
||||||
#include <QList>
|
|
||||||
#include <QVariant>
|
|
||||||
#include <QString>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QLocale>
|
|
||||||
#include <QMessageBox>
|
|
||||||
#include <QMenu>
|
|
||||||
#include <QAction>
|
|
||||||
#include <QRect>
|
|
||||||
#include <QSize>
|
|
||||||
#include <QToolTip>
|
|
||||||
#include <QWhatsThis>
|
|
||||||
|
|
||||||
#include "core/application.h"
|
|
||||||
#include "core/iconloader.h"
|
|
||||||
#include "core/mimedata.h"
|
|
||||||
#include "core/utilities.h"
|
|
||||||
#include "collection/collectiondirectorymodel.h"
|
|
||||||
#include "collection/collectionmodel.h"
|
|
||||||
#include "collection/collectionitem.h"
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
# include "device/devicemanager.h"
|
|
||||||
# include "device/devicestatefiltermodel.h"
|
|
||||||
#endif
|
|
||||||
#include "dialogs/edittagdialog.h"
|
|
||||||
#include "organize/organizedialog.h"
|
|
||||||
|
|
||||||
#include "contextalbumsmodel.h"
|
|
||||||
#include "contextalbumsview.h"
|
|
||||||
|
|
||||||
ContextItemDelegate::ContextItemDelegate(QObject *parent) : QStyledItemDelegate(parent) {}
|
|
||||||
|
|
||||||
bool ContextItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &idx) {
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
Q_UNUSED(option);
|
|
||||||
|
|
||||||
if (!event || !view) return false;
|
|
||||||
|
|
||||||
QString text = displayText(idx.data(), QLocale::system());
|
|
||||||
|
|
||||||
if (text.isEmpty() || !event) return false;
|
|
||||||
|
|
||||||
switch (event->type()) {
|
|
||||||
case QEvent::ToolTip: {
|
|
||||||
|
|
||||||
QSize real_text = sizeHint(option, idx);
|
|
||||||
QRect displayed_text = view->visualRect(idx);
|
|
||||||
bool is_elided = displayed_text.width() < real_text.width();
|
|
||||||
|
|
||||||
if (is_elided) {
|
|
||||||
QToolTip::showText(event->globalPos(), text, view);
|
|
||||||
}
|
|
||||||
else if (idx.data(Qt::ToolTipRole).isValid()) {
|
|
||||||
// If the item has a tooltip text, display it
|
|
||||||
QString tooltip_text = idx.data(Qt::ToolTipRole).toString();
|
|
||||||
QToolTip::showText(event->globalPos(), tooltip_text, view);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// in case that another text was previously displayed
|
|
||||||
QToolTip::hideText();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case QEvent::QueryWhatsThis:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case QEvent::WhatsThis:
|
|
||||||
QWhatsThis::showText(event->globalPos(), text, view);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ContextAlbumsView::ContextAlbumsView(QWidget *parent)
|
|
||||||
: AutoExpandingTreeView(parent),
|
|
||||||
app_(nullptr),
|
|
||||||
context_menu_(nullptr),
|
|
||||||
load_(nullptr),
|
|
||||||
add_to_playlist_(nullptr),
|
|
||||||
add_to_playlist_enqueue_(nullptr),
|
|
||||||
open_in_new_playlist_(nullptr),
|
|
||||||
organize_(nullptr),
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
copy_to_device_(nullptr),
|
|
||||||
#endif
|
|
||||||
edit_track_(nullptr),
|
|
||||||
edit_tracks_(nullptr),
|
|
||||||
show_in_browser_(nullptr),
|
|
||||||
is_in_keyboard_search_(false),
|
|
||||||
model_(nullptr) {
|
|
||||||
|
|
||||||
setStyleSheet("border: none;");
|
|
||||||
|
|
||||||
setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
|
|
||||||
setItemDelegate(new ContextItemDelegate(this));
|
|
||||||
setAttribute(Qt::WA_MacShowFocusRect, false);
|
|
||||||
setHeaderHidden(true);
|
|
||||||
setAllColumnsShowFocus(true);
|
|
||||||
setDragEnabled(true);
|
|
||||||
setDragDropMode(QAbstractItemView::DragOnly);
|
|
||||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
||||||
SetAddOnDoubleClick(false);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ContextAlbumsView::~ContextAlbumsView() = default;
|
|
||||||
|
|
||||||
void ContextAlbumsView::SaveFocus() {
|
|
||||||
|
|
||||||
QModelIndex current = currentIndex();
|
|
||||||
QVariant type = model()->data(current, ContextAlbumsModel::Role_Type);
|
|
||||||
if (!type.isValid() || !(type.toInt() == CollectionItem::Type_Song || type.toInt() == CollectionItem::Type_Container || type.toInt() == CollectionItem::Type_Divider)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
last_selected_path_.clear();
|
|
||||||
last_selected_song_ = Song();
|
|
||||||
last_selected_container_ = QString();
|
|
||||||
|
|
||||||
switch (type.toInt()) {
|
|
||||||
case CollectionItem::Type_Song: {
|
|
||||||
QModelIndex index = current;
|
|
||||||
SongList songs = model_->GetChildSongs(index);
|
|
||||||
if (!songs.isEmpty()) {
|
|
||||||
last_selected_song_ = songs.last();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case CollectionItem::Type_Container:
|
|
||||||
case CollectionItem::Type_Divider: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveContainerPath(current);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::SaveContainerPath(const QModelIndex &child) {
|
|
||||||
|
|
||||||
QModelIndex current = model()->parent(child);
|
|
||||||
QVariant type = model()->data(current, ContextAlbumsModel::Role_Type);
|
|
||||||
if (!type.isValid() || !(type.toInt() == CollectionItem::Type_Container || type.toInt() == CollectionItem::Type_Divider)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString text = model()->data(current, ContextAlbumsModel::Role_SortText).toString();
|
|
||||||
last_selected_path_ << text;
|
|
||||||
SaveContainerPath(current);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::RestoreFocus() {
|
|
||||||
|
|
||||||
if (last_selected_container_.isEmpty() && last_selected_song_.url().isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
RestoreLevelFocus();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ContextAlbumsView::RestoreLevelFocus(const QModelIndex &parent) {
|
|
||||||
|
|
||||||
if (model()->canFetchMore(parent)) {
|
|
||||||
model()->fetchMore(parent);
|
|
||||||
}
|
|
||||||
int rows = model()->rowCount(parent);
|
|
||||||
for (int i = 0; i < rows; i++) {
|
|
||||||
QModelIndex current = model()->index(i, 0, parent);
|
|
||||||
QVariant type = model()->data(current, ContextAlbumsModel::Role_Type);
|
|
||||||
switch (type.toInt()) {
|
|
||||||
case CollectionItem::Type_Song:
|
|
||||||
if (!last_selected_song_.url().isEmpty()) {
|
|
||||||
QModelIndex index = qobject_cast<QSortFilterProxyModel*>(model())->mapToSource(current);
|
|
||||||
const SongList songs = model_->GetChildSongs(index);
|
|
||||||
if (std::any_of(songs.begin(), songs.end(), [this](const Song &song) { return song == last_selected_song_; })) {
|
|
||||||
setCurrentIndex(current);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::Init(Application *app) {
|
|
||||||
|
|
||||||
app_ = app;
|
|
||||||
|
|
||||||
model_ = new ContextAlbumsModel(app_->collection_backend(), app_, this);
|
|
||||||
model_->Reset();
|
|
||||||
|
|
||||||
setModel(model_);
|
|
||||||
|
|
||||||
QObject::connect(model_, &ContextAlbumsModel::modelAboutToBeReset, this, &ContextAlbumsView::SaveFocus);
|
|
||||||
QObject::connect(model_, &ContextAlbumsModel::modelReset, this, &ContextAlbumsView::RestoreFocus);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::paintEvent(QPaintEvent *event) {
|
|
||||||
QTreeView::paintEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::mouseReleaseEvent(QMouseEvent *e) {
|
|
||||||
QTreeView::mouseReleaseEvent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::contextMenuEvent(QContextMenuEvent *e) {
|
|
||||||
|
|
||||||
if (!context_menu_) {
|
|
||||||
context_menu_ = new QMenu(this);
|
|
||||||
|
|
||||||
add_to_playlist_ = context_menu_->addAction(IconLoader::Load("media-playback-start"), tr("Append to current playlist"), this, &ContextAlbumsView::AddToPlaylist);
|
|
||||||
load_ = context_menu_->addAction(IconLoader::Load("media-playback-start"), tr("Replace current playlist"), this, &ContextAlbumsView::Load);
|
|
||||||
open_in_new_playlist_ = context_menu_->addAction(IconLoader::Load("document-new"), tr("Open in new playlist"), this, &ContextAlbumsView::OpenInNewPlaylist);
|
|
||||||
|
|
||||||
context_menu_->addSeparator();
|
|
||||||
add_to_playlist_enqueue_ = context_menu_->addAction(IconLoader::Load("go-next"), tr("Queue track"), this, &ContextAlbumsView::AddToPlaylistEnqueue);
|
|
||||||
|
|
||||||
context_menu_->addSeparator();
|
|
||||||
organize_ = context_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organize files..."), this, &ContextAlbumsView::Organize);
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
copy_to_device_ = context_menu_->addAction(IconLoader::Load("device"), tr("Copy to device..."), this, &ContextAlbumsView::CopyToDevice);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
context_menu_->addSeparator();
|
|
||||||
edit_track_ = context_menu_->addAction(IconLoader::Load("edit-rename"), tr("Edit track information..."), this, &ContextAlbumsView::EditTracks);
|
|
||||||
edit_tracks_ = context_menu_->addAction(IconLoader::Load("edit-rename"), tr("Edit tracks information..."), this, &ContextAlbumsView::EditTracks);
|
|
||||||
show_in_browser_ = context_menu_->addAction(IconLoader::Load("document-open-folder"), tr("Show in file browser..."), this, &ContextAlbumsView::ShowInBrowser);
|
|
||||||
|
|
||||||
context_menu_->addSeparator();
|
|
||||||
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
copy_to_device_->setDisabled(app_->device_manager()->connected_devices_model()->rowCount() == 0);
|
|
||||||
QObject::connect(app_->device_manager()->connected_devices_model(), &DeviceStateFilterModel::IsEmptyChanged, copy_to_device_, &QAction::setDisabled);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
context_menu_index_ = indexAt(e->pos());
|
|
||||||
if (!context_menu_index_.isValid()) return;
|
|
||||||
QModelIndexList selected_indexes = selectionModel()->selectedRows();
|
|
||||||
|
|
||||||
int regular_elements = 0;
|
|
||||||
int regular_editable = 0;
|
|
||||||
|
|
||||||
for (const QModelIndex &idx : selected_indexes) {
|
|
||||||
regular_elements++;
|
|
||||||
if (model_->data(idx, ContextAlbumsModel::Role_Editable).toBool()) {
|
|
||||||
regular_editable++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: check if custom plugin actions should be enabled / visible
|
|
||||||
const int songs_selected = regular_elements;
|
|
||||||
const bool regular_elements_only = songs_selected == regular_elements && regular_elements > 0;
|
|
||||||
|
|
||||||
// in all modes
|
|
||||||
load_->setEnabled(songs_selected > 0);
|
|
||||||
add_to_playlist_->setEnabled(songs_selected > 0);
|
|
||||||
open_in_new_playlist_->setEnabled(songs_selected > 0);
|
|
||||||
add_to_playlist_enqueue_->setEnabled(songs_selected > 0);
|
|
||||||
|
|
||||||
// if neither edit_track not edit_tracks are available, we show disabled edit_track element
|
|
||||||
edit_track_->setVisible(regular_editable <= 1);
|
|
||||||
edit_track_->setEnabled(regular_editable == 1);
|
|
||||||
|
|
||||||
organize_->setVisible(regular_elements_only);
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
copy_to_device_->setVisible(regular_elements_only);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// only when all selected items are editable
|
|
||||||
organize_->setEnabled(regular_elements == regular_editable);
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
copy_to_device_->setEnabled(regular_elements == regular_editable);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
context_menu_->popup(e->globalPos());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::Load() {
|
|
||||||
|
|
||||||
QMimeData *q_mimedata = model()->mimeData(selectedIndexes());
|
|
||||||
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
|
|
||||||
mimedata->clear_first_ = true;
|
|
||||||
}
|
|
||||||
emit AddToPlaylistSignal(q_mimedata);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::AddToPlaylist() {
|
|
||||||
|
|
||||||
emit AddToPlaylistSignal(model()->mimeData(selectedIndexes()));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::AddToPlaylistEnqueue() {
|
|
||||||
|
|
||||||
QMimeData *q_mimedata = model()->mimeData(selectedIndexes());
|
|
||||||
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
|
|
||||||
mimedata->enqueue_now_ = true;
|
|
||||||
}
|
|
||||||
emit AddToPlaylistSignal(q_mimedata);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::OpenInNewPlaylist() {
|
|
||||||
|
|
||||||
QMimeData *q_mimedata = model()->mimeData(selectedIndexes());
|
|
||||||
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
|
|
||||||
mimedata->open_in_new_playlist_ = true;
|
|
||||||
}
|
|
||||||
emit AddToPlaylistSignal(q_mimedata);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::scrollTo(const QModelIndex &idx, ScrollHint hint) {
|
|
||||||
|
|
||||||
if (is_in_keyboard_search_) {
|
|
||||||
QTreeView::scrollTo(idx, QAbstractItemView::PositionAtTop);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
QTreeView::scrollTo(idx, hint);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SongList ContextAlbumsView::GetSelectedSongs() const {
|
|
||||||
QModelIndexList selected_indexes = selectionModel()->selectedRows();
|
|
||||||
return model_->GetChildSongs(selected_indexes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::Organize() {
|
|
||||||
|
|
||||||
if (!organize_dialog_) {
|
|
||||||
organize_dialog_ = std::make_unique<OrganizeDialog>(app_->task_manager(), app_->collection_backend(), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
organize_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
|
|
||||||
organize_dialog_->SetCopy(false);
|
|
||||||
if (organize_dialog_->SetSongs(GetSelectedSongs())) {
|
|
||||||
organize_dialog_->show();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
QMessageBox::warning(this, tr("Error"), tr("None of the selected songs were suitable for copying to a device"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::EditTracks() {
|
|
||||||
|
|
||||||
if (!edit_tag_dialog_) {
|
|
||||||
edit_tag_dialog_ = std::make_unique<EditTagDialog>(app_, this);
|
|
||||||
}
|
|
||||||
edit_tag_dialog_->SetSongs(GetSelectedSongs());
|
|
||||||
edit_tag_dialog_->show();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::CopyToDevice() {
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
if (!organize_dialog_) {
|
|
||||||
organize_dialog_ = std::make_unique<OrganizeDialog>(app_->task_manager(), nullptr, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
organize_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
|
|
||||||
organize_dialog_->SetCopy(true);
|
|
||||||
organize_dialog_->SetSongs(GetSelectedSongs());
|
|
||||||
organize_dialog_->show();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::ShowInBrowser() const {
|
|
||||||
|
|
||||||
const SongList songs = GetSelectedSongs();
|
|
||||||
QList<QUrl> urls;
|
|
||||||
urls.reserve(songs.count());
|
|
||||||
for (const Song &song : songs) {
|
|
||||||
urls << song.url();
|
|
||||||
}
|
|
||||||
|
|
||||||
Utilities::OpenInFileBrowser(urls);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This code was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
|
|
||||||
*
|
|
||||||
* Strawberry 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.
|
|
||||||
*
|
|
||||||
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CONTEXTALBUMSVIEW_H
|
|
||||||
#define CONTEXTALBUMSVIEW_H
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QAbstractItemModel>
|
|
||||||
#include <QAbstractItemView>
|
|
||||||
#include <QStyledItemDelegate>
|
|
||||||
#include <QStyleOption>
|
|
||||||
#include <QSet>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
#include "core/song.h"
|
|
||||||
#include "widgets/autoexpandingtreeview.h"
|
|
||||||
|
|
||||||
class QWidget;
|
|
||||||
class QMenu;
|
|
||||||
class QAction;
|
|
||||||
class QContextMenuEvent;
|
|
||||||
class QHelpEvent;
|
|
||||||
class QMouseEvent;
|
|
||||||
class QPaintEvent;
|
|
||||||
|
|
||||||
class Application;
|
|
||||||
class ContextAlbumsModel;
|
|
||||||
class EditTagDialog;
|
|
||||||
class OrganizeDialog;
|
|
||||||
|
|
||||||
class ContextItemDelegate : public QStyledItemDelegate {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ContextItemDelegate(QObject *parent);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &idx) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ContextAlbumsView : public AutoExpandingTreeView {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ContextAlbumsView(QWidget *parent = nullptr);
|
|
||||||
~ContextAlbumsView() override;
|
|
||||||
|
|
||||||
// Returns Songs currently selected in the collection view.
|
|
||||||
// Please note that the selection is recursive meaning that if for example an album is selected this will return all of it's songs.
|
|
||||||
SongList GetSelectedSongs() const;
|
|
||||||
|
|
||||||
void Init(Application *app);
|
|
||||||
|
|
||||||
// QTreeView
|
|
||||||
void scrollTo(const QModelIndex &idx, ScrollHint hint = EnsureVisible) override;
|
|
||||||
|
|
||||||
ContextAlbumsModel *albums_model() { return model_; }
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void SaveFocus();
|
|
||||||
void RestoreFocus();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// QWidget
|
|
||||||
void paintEvent(QPaintEvent *event) override;
|
|
||||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
|
||||||
void contextMenuEvent(QContextMenuEvent *e) override;
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void Load();
|
|
||||||
void AddToPlaylist();
|
|
||||||
void AddToPlaylistEnqueue();
|
|
||||||
void OpenInNewPlaylist();
|
|
||||||
void Organize();
|
|
||||||
void CopyToDevice();
|
|
||||||
void EditTracks();
|
|
||||||
void ShowInBrowser() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RecheckIsEmpty();
|
|
||||||
bool RestoreLevelFocus(const QModelIndex &parent = QModelIndex());
|
|
||||||
void SaveContainerPath(const QModelIndex &child);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Application *app_;
|
|
||||||
|
|
||||||
QMenu *context_menu_;
|
|
||||||
QModelIndex context_menu_index_;
|
|
||||||
QAction *load_;
|
|
||||||
QAction *add_to_playlist_;
|
|
||||||
QAction *add_to_playlist_enqueue_;
|
|
||||||
QAction *open_in_new_playlist_;
|
|
||||||
QAction *organize_;
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
QAction *copy_to_device_;
|
|
||||||
#endif
|
|
||||||
QAction *edit_track_;
|
|
||||||
QAction *edit_tracks_;
|
|
||||||
QAction *show_in_browser_;
|
|
||||||
|
|
||||||
std::unique_ptr<OrganizeDialog> organize_dialog_;
|
|
||||||
std::unique_ptr<EditTagDialog> edit_tag_dialog_;
|
|
||||||
|
|
||||||
bool is_in_keyboard_search_;
|
|
||||||
|
|
||||||
// Save focus
|
|
||||||
Song last_selected_song_;
|
|
||||||
QString last_selected_container_;
|
|
||||||
QSet<QString> last_selected_path_;
|
|
||||||
|
|
||||||
ContextAlbumsModel *model_;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CONTEXTALBUMSVIEW_H
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2013-2022, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include <QSpacerItem>
|
#include <QSpacerItem>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QTextEdit>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
#include <QContextMenuEvent>
|
#include <QContextMenuEvent>
|
||||||
@@ -50,8 +51,10 @@
|
|||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "core/player.h"
|
#include "core/player.h"
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
#include "core/utilities.h"
|
|
||||||
#include "core/iconloader.h"
|
#include "core/iconloader.h"
|
||||||
|
#include "utilities/strutils.h"
|
||||||
|
#include "utilities/timeutils.h"
|
||||||
|
#include "widgets/resizabletextedit.h"
|
||||||
#include "engine/engine_fwd.h"
|
#include "engine/engine_fwd.h"
|
||||||
#include "engine/enginebase.h"
|
#include "engine/enginebase.h"
|
||||||
#include "engine/enginetype.h"
|
#include "engine/enginetype.h"
|
||||||
@@ -66,8 +69,8 @@
|
|||||||
|
|
||||||
#include "contextview.h"
|
#include "contextview.h"
|
||||||
#include "contextalbum.h"
|
#include "contextalbum.h"
|
||||||
#include "contextalbumsmodel.h"
|
|
||||||
#include "contextalbumsview.h"
|
const int ContextView::kWidgetSpacing = 50;
|
||||||
|
|
||||||
ContextView::ContextView(QWidget *parent)
|
ContextView::ContextView(QWidget *parent)
|
||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
@@ -75,18 +78,17 @@ ContextView::ContextView(QWidget *parent)
|
|||||||
collectionview_(nullptr),
|
collectionview_(nullptr),
|
||||||
album_cover_choice_controller_(nullptr),
|
album_cover_choice_controller_(nullptr),
|
||||||
lyrics_fetcher_(nullptr),
|
lyrics_fetcher_(nullptr),
|
||||||
menu_(new QMenu(this)),
|
menu_options_(new QMenu(this)),
|
||||||
action_show_album_(nullptr),
|
action_show_album_(nullptr),
|
||||||
action_show_data_(nullptr),
|
action_show_data_(nullptr),
|
||||||
action_show_output_(nullptr),
|
action_show_output_(nullptr),
|
||||||
action_show_albums_(nullptr),
|
|
||||||
action_show_lyrics_(nullptr),
|
action_show_lyrics_(nullptr),
|
||||||
action_search_lyrics_(nullptr),
|
action_search_lyrics_(nullptr),
|
||||||
layout_container_(new QVBoxLayout()),
|
layout_container_(new QVBoxLayout()),
|
||||||
widget_scrollarea_(new QWidget(this)),
|
widget_scrollarea_(new QWidget(this)),
|
||||||
layout_scrollarea_(new QVBoxLayout()),
|
layout_scrollarea_(new QVBoxLayout()),
|
||||||
scrollarea_(new QScrollArea(this)),
|
scrollarea_(new QScrollArea(this)),
|
||||||
label_top_(new QLabel(this)),
|
textedit_top_(new ResizableTextEdit(this)),
|
||||||
widget_album_(new ContextAlbum(this)),
|
widget_album_(new ContextAlbum(this)),
|
||||||
widget_stacked_(new QStackedWidget(this)),
|
widget_stacked_(new QStackedWidget(this)),
|
||||||
widget_stop_(new QWidget(this)),
|
widget_stop_(new QWidget(this)),
|
||||||
@@ -94,19 +96,13 @@ ContextView::ContextView(QWidget *parent)
|
|||||||
layout_stop_(new QVBoxLayout()),
|
layout_stop_(new QVBoxLayout()),
|
||||||
layout_play_(new QVBoxLayout()),
|
layout_play_(new QVBoxLayout()),
|
||||||
label_stop_summary_(new QLabel(this)),
|
label_stop_summary_(new QLabel(this)),
|
||||||
spacer_stop_bottom_(new QSpacerItem(0, 20, QSizePolicy::Expanding, QSizePolicy::Expanding)),
|
|
||||||
widget_play_data_(new QWidget(this)),
|
widget_play_data_(new QWidget(this)),
|
||||||
widget_play_output_(new QWidget(this)),
|
widget_play_output_(new QWidget(this)),
|
||||||
layout_play_data_(new QGridLayout()),
|
layout_play_data_(new QGridLayout()),
|
||||||
layout_play_output_(new QGridLayout()),
|
layout_play_output_(new QGridLayout()),
|
||||||
label_play_albums_(new QLabel(this)),
|
textedit_play_lyrics_(new ResizableTextEdit(this)),
|
||||||
label_play_lyrics_(new QLabel(this)),
|
|
||||||
widget_albums_(new ContextAlbumsView(this)),
|
|
||||||
//spacer_play_album_(new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)),
|
|
||||||
spacer_play_output_(new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)),
|
spacer_play_output_(new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)),
|
||||||
spacer_play_data_(new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)),
|
spacer_play_data_(new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)),
|
||||||
spacer_play_albums_(new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)),
|
|
||||||
spacer_play_bottom_(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Expanding)),
|
|
||||||
label_filetype_title_(new QLabel(this)),
|
label_filetype_title_(new QLabel(this)),
|
||||||
label_length_title_(new QLabel(this)),
|
label_length_title_(new QLabel(this)),
|
||||||
label_samplerate_title_(new QLabel(this)),
|
label_samplerate_title_(new QLabel(this)),
|
||||||
@@ -125,12 +121,10 @@ ContextView::ContextView(QWidget *parent)
|
|||||||
label_engine_(new QLabel(this)),
|
label_engine_(new QLabel(this)),
|
||||||
label_device_icon_(new QLabel(this)),
|
label_device_icon_(new QLabel(this)),
|
||||||
label_engine_icon_(new QLabel(this)),
|
label_engine_icon_(new QLabel(this)),
|
||||||
spacer_bottom_(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Expanding)),
|
|
||||||
lyrics_tried_(false),
|
lyrics_tried_(false),
|
||||||
lyrics_id_(-1),
|
lyrics_id_(-1),
|
||||||
font_size_headline_(0),
|
font_size_headline_(0),
|
||||||
font_size_normal_(0),
|
font_size_normal_(0) {
|
||||||
prev_width_(0) {
|
|
||||||
|
|
||||||
setLayout(layout_container_);
|
setLayout(layout_container_);
|
||||||
|
|
||||||
@@ -143,23 +137,21 @@ ContextView::ContextView(QWidget *parent)
|
|||||||
scrollarea_->setWidget(widget_scrollarea_);
|
scrollarea_->setWidget(widget_scrollarea_);
|
||||||
scrollarea_->setContentsMargins(0, 0, 0, 0);
|
scrollarea_->setContentsMargins(0, 0, 0, 0);
|
||||||
scrollarea_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
scrollarea_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
|
scrollarea_->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
|
|
||||||
widget_scrollarea_->setObjectName("context-widget-scrollarea");
|
widget_scrollarea_->setObjectName("context-widget-scrollarea");
|
||||||
widget_scrollarea_->setLayout(layout_scrollarea_);
|
widget_scrollarea_->setLayout(layout_scrollarea_);
|
||||||
widget_scrollarea_->setContentsMargins(0, 0, 0, 0);
|
widget_scrollarea_->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
label_top_->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
textedit_top_->setReadOnly(true);
|
||||||
label_top_->setWordWrap(true);
|
textedit_top_->setFrameShape(QFrame::NoFrame);
|
||||||
label_top_->setMinimumHeight(50);
|
|
||||||
label_top_->setContentsMargins(0, 0, 32, 0);
|
|
||||||
label_top_->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
|
||||||
|
|
||||||
layout_scrollarea_->setObjectName("context-layout-scrollarea");
|
layout_scrollarea_->setObjectName("context-layout-scrollarea");
|
||||||
layout_scrollarea_->setContentsMargins(15, 15, 15, 15);
|
layout_scrollarea_->setContentsMargins(15, 15, 15, 15);
|
||||||
layout_scrollarea_->addWidget(label_top_);
|
layout_scrollarea_->addWidget(textedit_top_);
|
||||||
layout_scrollarea_->addWidget(widget_album_);
|
layout_scrollarea_->addWidget(widget_album_);
|
||||||
layout_scrollarea_->addWidget(widget_stacked_);
|
layout_scrollarea_->addWidget(widget_stacked_);
|
||||||
layout_scrollarea_->addSpacerItem(spacer_bottom_);
|
layout_scrollarea_->addSpacerItem(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Expanding));
|
||||||
|
|
||||||
widget_stacked_->setContentsMargins(0, 0, 0, 0);
|
widget_stacked_->setContentsMargins(0, 0, 0, 0);
|
||||||
widget_stacked_->addWidget(widget_stop_);
|
widget_stacked_->addWidget(widget_stop_);
|
||||||
@@ -176,9 +168,10 @@ ContextView::ContextView(QWidget *parent)
|
|||||||
|
|
||||||
// Stopped
|
// Stopped
|
||||||
|
|
||||||
layout_stop_->setContentsMargins(5, 0, 40, 0);
|
label_stop_summary_->setAlignment(Qt::AlignLeft | Qt::AlignTop);
|
||||||
|
|
||||||
|
layout_stop_->setContentsMargins(0, 0, 0, 0);
|
||||||
layout_stop_->addWidget(label_stop_summary_);
|
layout_stop_->addWidget(label_stop_summary_);
|
||||||
layout_stop_->addSpacerItem(spacer_stop_bottom_);
|
|
||||||
|
|
||||||
// Playing
|
// Playing
|
||||||
|
|
||||||
@@ -244,23 +237,17 @@ ContextView::ContextView(QWidget *parent)
|
|||||||
|
|
||||||
widget_play_data_->setLayout(layout_play_data_);
|
widget_play_data_->setLayout(layout_play_data_);
|
||||||
|
|
||||||
label_play_lyrics_->setWordWrap(true);
|
textedit_play_lyrics_->setReadOnly(true);
|
||||||
label_play_lyrics_->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
textedit_play_lyrics_->setFrameShape(QFrame::NoFrame);
|
||||||
|
textedit_play_lyrics_->hide();
|
||||||
|
|
||||||
widget_albums_->hide();
|
layout_play_->setContentsMargins(0, 0, 0, 0);
|
||||||
label_play_albums_->setWordWrap(true);
|
|
||||||
label_play_albums_->hide();
|
|
||||||
|
|
||||||
layout_play_->setContentsMargins(5, 0, 40, 0);
|
|
||||||
layout_play_->addWidget(widget_play_output_);
|
layout_play_->addWidget(widget_play_output_);
|
||||||
layout_play_->addSpacerItem(spacer_play_output_);
|
layout_play_->addSpacerItem(spacer_play_output_);
|
||||||
layout_play_->addWidget(widget_play_data_);
|
layout_play_->addWidget(widget_play_data_);
|
||||||
layout_play_->addSpacerItem(spacer_play_data_);
|
layout_play_->addSpacerItem(spacer_play_data_);
|
||||||
layout_play_->addWidget(label_play_albums_);
|
layout_play_->addWidget(textedit_play_lyrics_);
|
||||||
layout_play_->addWidget(widget_albums_);
|
layout_play_->addSpacerItem(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Expanding));
|
||||||
layout_play_->addSpacerItem(spacer_play_albums_);
|
|
||||||
layout_play_->addWidget(label_play_lyrics_);
|
|
||||||
layout_play_->addSpacerItem(spacer_play_bottom_);
|
|
||||||
|
|
||||||
labels_play_ << label_engine_title_
|
labels_play_ << label_engine_title_
|
||||||
<< label_device_title_
|
<< label_device_title_
|
||||||
@@ -268,9 +255,7 @@ ContextView::ContextView(QWidget *parent)
|
|||||||
<< label_length_title_
|
<< label_length_title_
|
||||||
<< label_samplerate_title_
|
<< label_samplerate_title_
|
||||||
<< label_bitdepth_title_
|
<< label_bitdepth_title_
|
||||||
<< label_bitrate_title_
|
<< label_bitrate_title_;
|
||||||
<< label_play_albums_
|
|
||||||
<< label_play_lyrics_;
|
|
||||||
|
|
||||||
labels_play_data_ << label_engine_icon_
|
labels_play_data_ << label_engine_icon_
|
||||||
<< label_engine_
|
<< label_engine_
|
||||||
@@ -280,25 +265,16 @@ ContextView::ContextView(QWidget *parent)
|
|||||||
<< label_length_
|
<< label_length_
|
||||||
<< label_samplerate_
|
<< label_samplerate_
|
||||||
<< label_bitdepth_
|
<< label_bitdepth_
|
||||||
<< label_bitrate_
|
<< label_bitrate_;
|
||||||
<< label_play_albums_
|
|
||||||
<< label_play_lyrics_;
|
|
||||||
|
|
||||||
labels_play_all_ = labels_play_ << labels_play_data_;
|
labels_play_all_ = labels_play_ << labels_play_data_;
|
||||||
|
|
||||||
|
textedit_play_ << textedit_play_lyrics_;
|
||||||
|
|
||||||
QObject::connect(widget_album_, &ContextAlbum::FadeStopFinished, this, &ContextView::FadeStopFinished);
|
QObject::connect(widget_album_, &ContextAlbum::FadeStopFinished, this, &ContextView::FadeStopFinished);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::resizeEvent(QResizeEvent*) {
|
|
||||||
|
|
||||||
if (width() != prev_width_) {
|
|
||||||
widget_album_->setFixedSize(width() - 15, width());
|
|
||||||
prev_width_ = width();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextView::Init(Application *app, CollectionView *collectionview, AlbumCoverChoiceController *album_cover_choice_controller) {
|
void ContextView::Init(Application *app, CollectionView *collectionview, AlbumCoverChoiceController *album_cover_choice_controller) {
|
||||||
|
|
||||||
app_ = app;
|
app_ = app;
|
||||||
@@ -306,7 +282,6 @@ void ContextView::Init(Application *app, CollectionView *collectionview, AlbumCo
|
|||||||
album_cover_choice_controller_ = album_cover_choice_controller;
|
album_cover_choice_controller_ = album_cover_choice_controller;
|
||||||
|
|
||||||
widget_album_->Init(this, album_cover_choice_controller_);
|
widget_album_->Init(this, album_cover_choice_controller_);
|
||||||
widget_albums_->Init(app_);
|
|
||||||
lyrics_fetcher_ = new LyricsFetcher(app_->lyrics_providers(), this);
|
lyrics_fetcher_ = new LyricsFetcher(app_->lyrics_providers(), this);
|
||||||
|
|
||||||
QObject::connect(collectionview_, &CollectionView::TotalSongCountUpdated_, this, &ContextView::UpdateNoSong);
|
QObject::connect(collectionview_, &CollectionView::TotalSongCountUpdated_, this, &ContextView::UpdateNoSong);
|
||||||
@@ -332,10 +307,6 @@ void ContextView::AddActions() {
|
|||||||
action_show_output_->setCheckable(true);
|
action_show_output_->setCheckable(true);
|
||||||
action_show_output_->setChecked(true);
|
action_show_output_->setChecked(true);
|
||||||
|
|
||||||
action_show_albums_ = new QAction(tr("Show albums by artist"), this);
|
|
||||||
action_show_albums_->setCheckable(true);
|
|
||||||
action_show_albums_->setChecked(false);
|
|
||||||
|
|
||||||
action_show_lyrics_ = new QAction(tr("Show song lyrics"), this);
|
action_show_lyrics_ = new QAction(tr("Show song lyrics"), this);
|
||||||
action_show_lyrics_->setCheckable(true);
|
action_show_lyrics_->setCheckable(true);
|
||||||
action_show_lyrics_->setChecked(true);
|
action_show_lyrics_->setChecked(true);
|
||||||
@@ -344,20 +315,18 @@ void ContextView::AddActions() {
|
|||||||
action_search_lyrics_->setCheckable(true);
|
action_search_lyrics_->setCheckable(true);
|
||||||
action_search_lyrics_->setChecked(true);
|
action_search_lyrics_->setChecked(true);
|
||||||
|
|
||||||
menu_->addAction(action_show_album_);
|
menu_options_->addAction(action_show_album_);
|
||||||
menu_->addAction(action_show_data_);
|
menu_options_->addAction(action_show_data_);
|
||||||
menu_->addAction(action_show_output_);
|
menu_options_->addAction(action_show_output_);
|
||||||
menu_->addAction(action_show_albums_);
|
menu_options_->addAction(action_show_lyrics_);
|
||||||
menu_->addAction(action_show_lyrics_);
|
menu_options_->addAction(action_search_lyrics_);
|
||||||
menu_->addAction(action_search_lyrics_);
|
menu_options_->addSeparator();
|
||||||
menu_->addSeparator();
|
|
||||||
|
|
||||||
ReloadSettings();
|
ReloadSettings();
|
||||||
|
|
||||||
QObject::connect(action_show_album_, &QAction::triggered, this, &ContextView::ActionShowAlbums);
|
QObject::connect(action_show_album_, &QAction::triggered, this, &ContextView::ActionShowAlbum);
|
||||||
QObject::connect(action_show_data_, &QAction::triggered, this, &ContextView::ActionShowData);
|
QObject::connect(action_show_data_, &QAction::triggered, this, &ContextView::ActionShowData);
|
||||||
QObject::connect(action_show_output_, &QAction::triggered, this, &ContextView::ActionShowOutput);
|
QObject::connect(action_show_output_, &QAction::triggered, this, &ContextView::ActionShowOutput);
|
||||||
QObject::connect(action_show_albums_, &QAction::triggered, this, &ContextView::ActionShowAlbums);
|
|
||||||
QObject::connect(action_show_lyrics_, &QAction::triggered, this, &ContextView::ActionShowLyrics);
|
QObject::connect(action_show_lyrics_, &QAction::triggered, this, &ContextView::ActionShowLyrics);
|
||||||
QObject::connect(action_search_lyrics_, &QAction::triggered, this, &ContextView::ActionSearchLyrics);
|
QObject::connect(action_search_lyrics_, &QAction::triggered, this, &ContextView::ActionSearchLyrics);
|
||||||
|
|
||||||
@@ -372,7 +341,6 @@ void ContextView::ReloadSettings() {
|
|||||||
action_show_album_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::ALBUM], true).toBool());
|
action_show_album_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::ALBUM], true).toBool());
|
||||||
action_show_data_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::TECHNICAL_DATA], false).toBool());
|
action_show_data_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::TECHNICAL_DATA], false).toBool());
|
||||||
action_show_output_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::ENGINE_AND_DEVICE], false).toBool());
|
action_show_output_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::ENGINE_AND_DEVICE], false).toBool());
|
||||||
action_show_albums_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::ALBUMS_BY_ARTIST], false).toBool());
|
|
||||||
action_show_lyrics_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::SONG_LYRICS], true).toBool());
|
action_show_lyrics_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::SONG_LYRICS], true).toBool());
|
||||||
action_search_lyrics_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::SEARCH_LYRICS], true).toBool());
|
action_search_lyrics_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::SEARCH_LYRICS], true).toBool());
|
||||||
font_headline_ = s.value("font_headline", font().family()).toString();
|
font_headline_ = s.value("font_headline", font().family()).toString();
|
||||||
@@ -392,6 +360,16 @@ void ContextView::ReloadSettings() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ContextView::resizeEvent(QResizeEvent *e) {
|
||||||
|
|
||||||
|
if (e->size().width() != e->oldSize().width()) {
|
||||||
|
widget_album_->UpdateWidth(width() - kWidgetSpacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget::resizeEvent(e);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void ContextView::Playing() {}
|
void ContextView::Playing() {}
|
||||||
|
|
||||||
void ContextView::Stopped() {
|
void ContextView::Stopped() {
|
||||||
@@ -439,6 +417,7 @@ void ContextView::FadeStopFinished() {
|
|||||||
widget_stacked_->setCurrentWidget(widget_stop_);
|
widget_stacked_->setCurrentWidget(widget_stop_);
|
||||||
NoSong();
|
NoSong();
|
||||||
ResetSong();
|
ResetSong();
|
||||||
|
widget_stacked_->updateGeometry();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,9 +435,8 @@ void ContextView::NoSong() {
|
|||||||
widget_album_->show();
|
widget_album_->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
label_top_->setStyleSheet("font: 20pt 'Open Sans', 'FreeSans', 'FreeSerif', 'Liberation Serif'; font-weight: Regular;");
|
textedit_top_->setFont(QFont(font_headline_, font_size_headline_ * 1.6));
|
||||||
|
textedit_top_->SetText(tr("No song playing"));
|
||||||
label_top_->setText(tr("No song playing"));
|
|
||||||
|
|
||||||
QString html;
|
QString html;
|
||||||
if (collectionview_->TotalSongs() == 1) html += tr("%1 song").arg(collectionview_->TotalSongs());
|
if (collectionview_->TotalSongs() == 1) html += tr("%1 song").arg(collectionview_->TotalSongs());
|
||||||
@@ -473,24 +451,28 @@ void ContextView::NoSong() {
|
|||||||
else html += tr("%1 albums").arg(collectionview_->TotalAlbums());
|
else html += tr("%1 albums").arg(collectionview_->TotalAlbums());
|
||||||
html += "<br />";
|
html += "<br />";
|
||||||
|
|
||||||
label_stop_summary_->setStyleSheet(QString("font: %1pt \"%2\"; font-weight: regular;").arg(font_size_normal_).arg(font_normal_));
|
label_stop_summary_->setFont(QFont(font_normal_, font_size_normal_));
|
||||||
label_stop_summary_->setText(html);
|
label_stop_summary_->setText(html);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::UpdateFonts() {
|
void ContextView::UpdateFonts() {
|
||||||
|
|
||||||
|
QFont font(font_normal_, font_size_normal_);
|
||||||
|
font.setBold(false);
|
||||||
for (QLabel *l : labels_play_all_) {
|
for (QLabel *l : labels_play_all_) {
|
||||||
l->setStyleSheet(QString("font: %2pt \"%1\"; font-weight: regular;").arg(font_normal_).arg(font_size_normal_));
|
l->setFont(font);
|
||||||
|
}
|
||||||
|
for (QTextEdit *e : textedit_play_) {
|
||||||
|
e->setFont(font);
|
||||||
}
|
}
|
||||||
label_play_albums_->setStyleSheet(QString("background-color: #3DADE8; color: rgb(255, 255, 255); font: %1pt \"%2\"; font-weight: regular;").arg(font_size_normal_).arg(font_normal_));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::SetSong() {
|
void ContextView::SetSong() {
|
||||||
|
|
||||||
label_top_->setStyleSheet(QString("font: %2pt \"%1\"; font-weight: regular;").arg(font_headline_).arg(font_size_headline_));
|
textedit_top_->setFont(QFont(font_headline_, font_size_headline_));
|
||||||
label_top_->setText(QString("<b>%1</b><br />%2").arg(Utilities::ReplaceMessage(title_fmt_, song_playing_, "<br />", true), Utilities::ReplaceMessage(summary_fmt_, song_playing_, "<br />", true)));
|
textedit_top_->SetText(QString("<b>%1</b><br />%2").arg(Utilities::ReplaceMessage(title_fmt_, song_playing_, "<br />", true), Utilities::ReplaceMessage(summary_fmt_, song_playing_, "<br />", true)));
|
||||||
|
|
||||||
label_stop_summary_->clear();
|
label_stop_summary_->clear();
|
||||||
|
|
||||||
@@ -564,7 +546,7 @@ void ContextView::SetSong() {
|
|||||||
widget_play_output_->show();
|
widget_play_output_->show();
|
||||||
Engine::EngineType enginetype(Engine::None);
|
Engine::EngineType enginetype(Engine::None);
|
||||||
if (app_->player()->engine()) enginetype = app_->player()->engine()->type();
|
if (app_->player()->engine()) enginetype = app_->player()->engine()->type();
|
||||||
QIcon icon_engine = IconLoader::Load(EngineName(enginetype), 32);
|
QIcon icon_engine = IconLoader::Load(EngineName(enginetype), true, 32);
|
||||||
|
|
||||||
label_engine_icon_->setPixmap(icon_engine.pixmap(QSize(32, 32)));
|
label_engine_icon_->setPixmap(icon_engine.pixmap(QSize(32, 32)));
|
||||||
label_engine_->setText(EngineDescription(enginetype));
|
label_engine_->setText(EngineDescription(enginetype));
|
||||||
@@ -582,7 +564,7 @@ void ContextView::SetSong() {
|
|||||||
label_device_title_->show();
|
label_device_title_->show();
|
||||||
label_device_icon_->show();
|
label_device_icon_->show();
|
||||||
label_device_->show();
|
label_device_->show();
|
||||||
QIcon icon_device = IconLoader::Load(device.iconname, 32);
|
QIcon icon_device = IconLoader::Load(device.iconname, true, 32);
|
||||||
label_device_icon_->setPixmap(icon_device.pixmap(QSize(32, 32)));
|
label_device_icon_->setPixmap(icon_device.pixmap(QSize(32, 32)));
|
||||||
label_device_->setText(device.description);
|
label_device_->setText(device.description);
|
||||||
}
|
}
|
||||||
@@ -603,51 +585,23 @@ void ContextView::SetSong() {
|
|||||||
spacer_play_output_->changeSize(0, 0, QSizePolicy::Fixed);
|
spacer_play_output_->changeSize(0, 0, QSizePolicy::Fixed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action_show_albums_->isChecked() && song_prev_.artist() != song_playing_.artist()) {
|
if (action_show_lyrics_->isChecked() && !lyrics_.isEmpty()) {
|
||||||
CollectionBackend::AlbumList albumlist;
|
textedit_play_lyrics_->SetText(lyrics_);
|
||||||
widget_albums_->albums_model()->Reset();
|
textedit_play_lyrics_->show();
|
||||||
albumlist = app_->collection_backend()->GetAlbumsByArtist(song_playing_.effective_albumartist());
|
|
||||||
if (albumlist.count() > 1) {
|
|
||||||
label_play_albums_->show();
|
|
||||||
widget_albums_->show();
|
|
||||||
label_play_albums_->setText("<b>" + tr("Albums by %1").arg(song_playing_.effective_albumartist().toHtmlEscaped()) + "</b>");
|
|
||||||
for (const CollectionBackend::Album &album : albumlist) {
|
|
||||||
SongList songs = app_->collection_backend()->GetAlbumSongs(song_playing_.effective_albumartist(), album.album);
|
|
||||||
widget_albums_->albums_model()->AddSongs(songs);
|
|
||||||
}
|
|
||||||
spacer_play_albums_->changeSize(20, 10, QSizePolicy::Fixed);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
label_play_albums_->hide();
|
|
||||||
widget_albums_->hide();
|
|
||||||
label_play_albums_->clear();
|
|
||||||
spacer_play_albums_->changeSize(0, 0, QSizePolicy::Fixed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!action_show_albums_->isChecked()) {
|
|
||||||
label_play_albums_->hide();
|
|
||||||
widget_albums_->hide();
|
|
||||||
label_play_albums_->clear();
|
|
||||||
widget_albums_->albums_model()->Reset();
|
|
||||||
spacer_play_albums_->changeSize(0, 0, QSizePolicy::Fixed);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action_show_lyrics_->isChecked()) {
|
|
||||||
label_play_lyrics_->show();
|
|
||||||
label_play_lyrics_->setText(lyrics_);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
label_play_lyrics_->hide();
|
textedit_play_lyrics_->clear();
|
||||||
label_play_lyrics_->clear();
|
textedit_play_lyrics_->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
widget_stacked_->setCurrentWidget(widget_play_);
|
widget_stacked_->setCurrentWidget(widget_play_);
|
||||||
|
widget_stacked_->updateGeometry();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::UpdateSong(const Song &song) {
|
void ContextView::UpdateSong(const Song &song) {
|
||||||
|
|
||||||
label_top_->setText(QString("<b>%1</b><br />%2").arg(Utilities::ReplaceMessage(title_fmt_, song, "<br />", true), Utilities::ReplaceMessage(summary_fmt_, song, "<br />", true)));
|
textedit_top_->SetText(QString("<b>%1</b><br />%2").arg(Utilities::ReplaceMessage(title_fmt_, song, "<br />", true), Utilities::ReplaceMessage(summary_fmt_, song, "<br />", true)));
|
||||||
|
|
||||||
if (action_show_data_->isChecked()) {
|
if (action_show_data_->isChecked()) {
|
||||||
if (song.filetype() != song_playing_.filetype()) label_filetype_->setText(song.TextForFiletype());
|
if (song.filetype() != song_playing_.filetype()) label_filetype_->setText(song.TextForFiletype());
|
||||||
@@ -703,6 +657,8 @@ void ContextView::UpdateSong(const Song &song) {
|
|||||||
|
|
||||||
song_playing_ = song;
|
song_playing_ = song;
|
||||||
|
|
||||||
|
widget_stacked_->updateGeometry();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::ResetSong() {
|
void ContextView::ResetSong() {
|
||||||
@@ -711,22 +667,43 @@ void ContextView::ResetSong() {
|
|||||||
l->clear();
|
l->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (QTextEdit *l : textedit_play_) {
|
||||||
|
l->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
widget_play_output_->hide();
|
||||||
|
widget_play_data_->hide();
|
||||||
|
textedit_play_lyrics_->hide();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::UpdateLyrics(const quint64 id, const QString &provider, const QString &lyrics) {
|
void ContextView::UpdateLyrics(const quint64 id, const QString &provider, const QString &lyrics) {
|
||||||
|
|
||||||
if (static_cast<qint64>(id) != lyrics_id_) return;
|
if (static_cast<qint64>(id) != lyrics_id_) return;
|
||||||
|
|
||||||
lyrics_ = lyrics + "\n\n(Lyrics from " + provider + ")\n";
|
lyrics_ = lyrics + "\n\n(Lyrics from " + provider + ")\n";
|
||||||
lyrics_id_ = -1;
|
lyrics_id_ = -1;
|
||||||
if (action_show_lyrics_->isChecked()) {
|
|
||||||
label_play_lyrics_->setText(lyrics_);
|
if (action_show_lyrics_->isChecked() && !lyrics_.isEmpty()) {
|
||||||
|
textedit_play_lyrics_->SetText(lyrics_);
|
||||||
|
textedit_play_lyrics_->show();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
textedit_play_lyrics_->clear();
|
||||||
|
textedit_play_lyrics_->hide();
|
||||||
}
|
}
|
||||||
else label_play_lyrics_->clear();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::contextMenuEvent(QContextMenuEvent *e) {
|
void ContextView::contextMenuEvent(QContextMenuEvent *e) {
|
||||||
if (menu_) menu_->popup(mapToGlobal(e->pos()));
|
|
||||||
|
if (menu_options_ && widget_stacked_->currentWidget() == widget_stop_) {
|
||||||
|
menu_options_->popup(mapToGlobal(e->pos()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
QWidget::contextMenuEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::dragEnterEvent(QDragEnterEvent *e) {
|
void ContextView::dragEnterEvent(QDragEnterEvent *e) {
|
||||||
@@ -788,17 +765,6 @@ void ContextView::ActionShowOutput() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::ActionShowAlbums() {
|
|
||||||
|
|
||||||
QSettings s;
|
|
||||||
s.beginGroup(ContextSettingsPage::kSettingsGroup);
|
|
||||||
s.setValue(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::ALBUMS_BY_ARTIST], action_show_albums_->isChecked());
|
|
||||||
s.endGroup();
|
|
||||||
song_prev_ = Song();
|
|
||||||
if (song_playing_.is_valid()) SetSong();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextView::ActionShowLyrics() {
|
void ContextView::ActionShowLyrics() {
|
||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2013-2022, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -45,10 +45,10 @@ class QContextMenuEvent;
|
|||||||
class QDragEnterEvent;
|
class QDragEnterEvent;
|
||||||
class QDropEvent;
|
class QDropEvent;
|
||||||
|
|
||||||
|
class ResizableTextEdit;
|
||||||
class Application;
|
class Application;
|
||||||
class CollectionView;
|
class CollectionView;
|
||||||
class AlbumCoverChoiceController;
|
class AlbumCoverChoiceController;
|
||||||
class ContextAlbumsView;
|
|
||||||
class LyricsFetcher;
|
class LyricsFetcher;
|
||||||
|
|
||||||
class ContextView : public QWidget {
|
class ContextView : public QWidget {
|
||||||
@@ -60,12 +60,11 @@ class ContextView : public QWidget {
|
|||||||
void Init(Application *app, CollectionView *collectionview, AlbumCoverChoiceController *album_cover_choice_controller);
|
void Init(Application *app, CollectionView *collectionview, AlbumCoverChoiceController *album_cover_choice_controller);
|
||||||
|
|
||||||
ContextAlbum *album_widget() const { return widget_album_; }
|
ContextAlbum *album_widget() const { return widget_album_; }
|
||||||
ContextAlbumsView *albums_widget() const { return widget_albums_; }
|
|
||||||
bool album_enabled() const { return action_show_album_->isChecked(); }
|
bool album_enabled() const { return action_show_album_->isChecked(); }
|
||||||
Song song_playing() const { return song_playing_; }
|
Song song_playing() const { return song_playing_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent*) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
void contextMenuEvent(QContextMenuEvent*) override;
|
void contextMenuEvent(QContextMenuEvent*) override;
|
||||||
void dragEnterEvent(QDragEnterEvent*) override;
|
void dragEnterEvent(QDragEnterEvent*) override;
|
||||||
void dropEvent(QDropEvent*) override;
|
void dropEvent(QDropEvent*) override;
|
||||||
@@ -88,7 +87,6 @@ class ContextView : public QWidget {
|
|||||||
void ActionShowAlbum();
|
void ActionShowAlbum();
|
||||||
void ActionShowData();
|
void ActionShowData();
|
||||||
void ActionShowOutput();
|
void ActionShowOutput();
|
||||||
void ActionShowAlbums();
|
|
||||||
void ActionShowLyrics();
|
void ActionShowLyrics();
|
||||||
void ActionSearchLyrics();
|
void ActionSearchLyrics();
|
||||||
void UpdateNoSong();
|
void UpdateNoSong();
|
||||||
@@ -104,16 +102,17 @@ class ContextView : public QWidget {
|
|||||||
void AlbumCoverLoaded(const Song &song, const QImage &image);
|
void AlbumCoverLoaded(const Song &song, const QImage &image);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static const int kWidgetSpacing;
|
||||||
|
|
||||||
Application *app_;
|
Application *app_;
|
||||||
CollectionView *collectionview_;
|
CollectionView *collectionview_;
|
||||||
AlbumCoverChoiceController *album_cover_choice_controller_;
|
AlbumCoverChoiceController *album_cover_choice_controller_;
|
||||||
LyricsFetcher *lyrics_fetcher_;
|
LyricsFetcher *lyrics_fetcher_;
|
||||||
|
|
||||||
QMenu *menu_;
|
QMenu *menu_options_;
|
||||||
QAction *action_show_album_;
|
QAction *action_show_album_;
|
||||||
QAction *action_show_data_;
|
QAction *action_show_data_;
|
||||||
QAction *action_show_output_;
|
QAction *action_show_output_;
|
||||||
QAction *action_show_albums_;
|
|
||||||
QAction *action_show_lyrics_;
|
QAction *action_show_lyrics_;
|
||||||
QAction *action_search_lyrics_;
|
QAction *action_search_lyrics_;
|
||||||
|
|
||||||
@@ -121,7 +120,7 @@ class ContextView : public QWidget {
|
|||||||
QWidget *widget_scrollarea_;
|
QWidget *widget_scrollarea_;
|
||||||
QVBoxLayout *layout_scrollarea_;
|
QVBoxLayout *layout_scrollarea_;
|
||||||
QScrollArea *scrollarea_;
|
QScrollArea *scrollarea_;
|
||||||
QLabel *label_top_;
|
ResizableTextEdit *textedit_top_;
|
||||||
ContextAlbum *widget_album_;
|
ContextAlbum *widget_album_;
|
||||||
QStackedWidget *widget_stacked_;
|
QStackedWidget *widget_stacked_;
|
||||||
QWidget *widget_stop_;
|
QWidget *widget_stop_;
|
||||||
@@ -129,20 +128,14 @@ class ContextView : public QWidget {
|
|||||||
QVBoxLayout *layout_stop_;
|
QVBoxLayout *layout_stop_;
|
||||||
QVBoxLayout *layout_play_;
|
QVBoxLayout *layout_play_;
|
||||||
QLabel *label_stop_summary_;
|
QLabel *label_stop_summary_;
|
||||||
QSpacerItem *spacer_stop_bottom_;
|
|
||||||
QWidget *widget_play_data_;
|
QWidget *widget_play_data_;
|
||||||
QWidget *widget_play_output_;
|
QWidget *widget_play_output_;
|
||||||
QGridLayout *layout_play_data_;
|
QGridLayout *layout_play_data_;
|
||||||
QGridLayout *layout_play_output_;
|
QGridLayout *layout_play_output_;
|
||||||
QLabel *label_play_albums_;
|
ResizableTextEdit *textedit_play_lyrics_;
|
||||||
QLabel *label_play_lyrics_;
|
|
||||||
ContextAlbumsView *widget_albums_;
|
|
||||||
|
|
||||||
//QSpacerItem *spacer_play_album_;
|
|
||||||
QSpacerItem *spacer_play_output_;
|
QSpacerItem *spacer_play_output_;
|
||||||
QSpacerItem *spacer_play_data_;
|
QSpacerItem *spacer_play_data_;
|
||||||
QSpacerItem *spacer_play_albums_;
|
|
||||||
QSpacerItem *spacer_play_bottom_;
|
|
||||||
|
|
||||||
QLabel *label_filetype_title_;
|
QLabel *label_filetype_title_;
|
||||||
QLabel *label_length_title_;
|
QLabel *label_length_title_;
|
||||||
@@ -165,8 +158,6 @@ class ContextView : public QWidget {
|
|||||||
QLabel *label_device_icon_;
|
QLabel *label_device_icon_;
|
||||||
QLabel *label_engine_icon_;
|
QLabel *label_engine_icon_;
|
||||||
|
|
||||||
QSpacerItem *spacer_bottom_;
|
|
||||||
|
|
||||||
Song song_playing_;
|
Song song_playing_;
|
||||||
Song song_prev_;
|
Song song_prev_;
|
||||||
QImage image_original_;
|
QImage image_original_;
|
||||||
@@ -181,11 +172,10 @@ class ContextView : public QWidget {
|
|||||||
qreal font_size_normal_;
|
qreal font_size_normal_;
|
||||||
|
|
||||||
QList<QLabel*> labels_play_;
|
QList<QLabel*> labels_play_;
|
||||||
|
QList<ResizableTextEdit*> textedit_play_;
|
||||||
QList<QLabel*> labels_play_data_;
|
QList<QLabel*> labels_play_data_;
|
||||||
QList<QLabel*> labels_play_all_;
|
QList<QLabel*> labels_play_all_;
|
||||||
|
|
||||||
int prev_width_;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONTEXTVIEW_H
|
#endif // CONTEXTVIEW_H
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This file was part of Clementine.
|
|
||||||
* Copyright 2012, Arnaud Bienner <arnaud.bienner@gmail.com>
|
|
||||||
*
|
|
||||||
* Strawberry 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.
|
|
||||||
*
|
|
||||||
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QVariant>
|
|
||||||
#include <QPalette>
|
|
||||||
#include <QColor>
|
|
||||||
#include <QSettings>
|
|
||||||
|
|
||||||
#include "appearance.h"
|
|
||||||
#include "settings/appearancesettingspage.h"
|
|
||||||
|
|
||||||
const QPalette Appearance::kDefaultPalette = QPalette();
|
|
||||||
|
|
||||||
Appearance::Appearance(QObject *parent) : QObject(parent) {
|
|
||||||
|
|
||||||
QPalette p = QApplication::palette();
|
|
||||||
|
|
||||||
QSettings s;
|
|
||||||
s.beginGroup(AppearanceSettingsPage::kSettingsGroup);
|
|
||||||
background_color_ = s.value(AppearanceSettingsPage::kBackgroundColor, p.color(QPalette::WindowText)).value<QColor>();
|
|
||||||
foreground_color_ = s.value(AppearanceSettingsPage::kForegroundColor, p.color(QPalette::Window)).value<QColor>();
|
|
||||||
s.endGroup();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Appearance::LoadUserTheme() {
|
|
||||||
|
|
||||||
QSettings s;
|
|
||||||
s.beginGroup(AppearanceSettingsPage::kSettingsGroup);
|
|
||||||
bool use_a_custom_color_set = s.value(AppearanceSettingsPage::kUseCustomColorSet).toBool();
|
|
||||||
s.endGroup();
|
|
||||||
|
|
||||||
if (use_a_custom_color_set) {
|
|
||||||
ChangeForegroundColor(foreground_color_);
|
|
||||||
ChangeBackgroundColor(background_color_);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Appearance::ResetToSystemDefaultTheme() {
|
|
||||||
QApplication::setPalette(kDefaultPalette);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Appearance::ChangeForegroundColor(const QColor &color) {
|
|
||||||
|
|
||||||
// Get the application palette
|
|
||||||
QPalette p = QApplication::palette();
|
|
||||||
|
|
||||||
// Modify the palette
|
|
||||||
p.setColor(QPalette::WindowText, color);
|
|
||||||
p.setColor(QPalette::Text, color);
|
|
||||||
|
|
||||||
// Make the modified palette the new application's palette
|
|
||||||
QApplication::setPalette(p);
|
|
||||||
foreground_color_ = color;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Appearance::ChangeBackgroundColor(const QColor &color) {
|
|
||||||
|
|
||||||
// Get the application palette
|
|
||||||
QPalette p = QApplication::palette();
|
|
||||||
|
|
||||||
// Modify the palette
|
|
||||||
p.setColor(QPalette::Window, color);
|
|
||||||
p.setColor(QPalette::Base, color);
|
|
||||||
|
|
||||||
// Make the modified palette the new application's palette
|
|
||||||
QApplication::setPalette(p);
|
|
||||||
background_color_ = color;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -29,18 +29,15 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QVariant>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include "core/lazy.h"
|
#include "core/lazy.h"
|
||||||
#include "core/tagreaderclient.h"
|
#include "core/tagreaderclient.h"
|
||||||
#include "core/song.h"
|
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
|
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
#include "taskmanager.h"
|
#include "taskmanager.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "appearance.h"
|
|
||||||
|
|
||||||
#include "engine/devicefinders.h"
|
#include "engine/devicefinders.h"
|
||||||
#ifndef Q_OS_WIN
|
#ifndef Q_OS_WIN
|
||||||
@@ -99,33 +96,32 @@ using namespace std::chrono_literals;
|
|||||||
class ApplicationImpl {
|
class ApplicationImpl {
|
||||||
public:
|
public:
|
||||||
explicit ApplicationImpl(Application *app) :
|
explicit ApplicationImpl(Application *app) :
|
||||||
tag_reader_client_([=]() {
|
tag_reader_client_([app]() {
|
||||||
TagReaderClient *client = new TagReaderClient(app);
|
TagReaderClient *client = new TagReaderClient(app);
|
||||||
app->MoveToNewThread(client);
|
app->MoveToNewThread(client);
|
||||||
client->Start();
|
client->Start();
|
||||||
return client;
|
return client;
|
||||||
}),
|
}),
|
||||||
database_([=]() {
|
database_([app]() {
|
||||||
Database *db = new Database(app, app);
|
Database *db = new Database(app, app);
|
||||||
app->MoveToNewThread(db);
|
app->MoveToNewThread(db);
|
||||||
QTimer::singleShot(30s, db, &Database::DoBackup);
|
QTimer::singleShot(30s, db, &Database::DoBackup);
|
||||||
return db;
|
return db;
|
||||||
}),
|
}),
|
||||||
appearance_([=]() { return new Appearance(app); }),
|
task_manager_([app]() { return new TaskManager(app); }),
|
||||||
task_manager_([=]() { return new TaskManager(app); }),
|
player_([app]() { return new Player(app, app); }),
|
||||||
player_([=]() { return new Player(app, app); }),
|
device_finders_([app]() { return new DeviceFinders(app); }),
|
||||||
device_finders_([=]() { return new DeviceFinders(app); }),
|
|
||||||
#ifndef Q_OS_WIN
|
#ifndef Q_OS_WIN
|
||||||
device_manager_([=]() { return new DeviceManager(app, app); }),
|
device_manager_([app]() { return new DeviceManager(app, app); }),
|
||||||
#endif
|
#endif
|
||||||
collection_([=]() { return new SCollection(app, app); }),
|
collection_([app]() { return new SCollection(app, app); }),
|
||||||
playlist_backend_([=]() {
|
playlist_backend_([this, app]() {
|
||||||
PlaylistBackend *backend = new PlaylistBackend(app, app);
|
PlaylistBackend *backend = new PlaylistBackend(app, app);
|
||||||
app->MoveToThread(backend, database_->thread());
|
app->MoveToThread(backend, database_->thread());
|
||||||
return backend;
|
return backend;
|
||||||
}),
|
}),
|
||||||
playlist_manager_([=]() { return new PlaylistManager(app); }),
|
playlist_manager_([app]() { return new PlaylistManager(app); }),
|
||||||
cover_providers_([=]() {
|
cover_providers_([app]() {
|
||||||
CoverProviders *cover_providers = new CoverProviders(app);
|
CoverProviders *cover_providers = new CoverProviders(app);
|
||||||
// Initialize the repository of cover providers.
|
// Initialize the repository of cover providers.
|
||||||
cover_providers->AddProvider(new LastFmCoverProvider(app, cover_providers->network(), app));
|
cover_providers->AddProvider(new LastFmCoverProvider(app, cover_providers->network(), app));
|
||||||
@@ -143,13 +139,13 @@ class ApplicationImpl {
|
|||||||
cover_providers->ReloadSettings();
|
cover_providers->ReloadSettings();
|
||||||
return cover_providers;
|
return cover_providers;
|
||||||
}),
|
}),
|
||||||
album_cover_loader_([=]() {
|
album_cover_loader_([app]() {
|
||||||
AlbumCoverLoader *loader = new AlbumCoverLoader(app);
|
AlbumCoverLoader *loader = new AlbumCoverLoader(app);
|
||||||
app->MoveToNewThread(loader);
|
app->MoveToNewThread(loader);
|
||||||
return loader;
|
return loader;
|
||||||
}),
|
}),
|
||||||
current_albumcover_loader_([=]() { return new CurrentAlbumCoverLoader(app, app); }),
|
current_albumcover_loader_([app]() { return new CurrentAlbumCoverLoader(app, app); }),
|
||||||
lyrics_providers_([=]() {
|
lyrics_providers_([app]() {
|
||||||
LyricsProviders *lyrics_providers = new LyricsProviders(app);
|
LyricsProviders *lyrics_providers = new LyricsProviders(app);
|
||||||
// Initialize the repository of lyrics providers.
|
// Initialize the repository of lyrics providers.
|
||||||
lyrics_providers->AddProvider(new AuddLyricsProvider(lyrics_providers->network(), app));
|
lyrics_providers->AddProvider(new AuddLyricsProvider(lyrics_providers->network(), app));
|
||||||
@@ -161,7 +157,7 @@ class ApplicationImpl {
|
|||||||
lyrics_providers->ReloadSettings();
|
lyrics_providers->ReloadSettings();
|
||||||
return lyrics_providers;
|
return lyrics_providers;
|
||||||
}),
|
}),
|
||||||
internet_services_([=]() {
|
internet_services_([app]() {
|
||||||
InternetServices *internet_services = new InternetServices(app);
|
InternetServices *internet_services = new InternetServices(app);
|
||||||
#ifdef HAVE_SUBSONIC
|
#ifdef HAVE_SUBSONIC
|
||||||
internet_services->AddService(new SubsonicService(app, internet_services));
|
internet_services->AddService(new SubsonicService(app, internet_services));
|
||||||
@@ -174,18 +170,17 @@ class ApplicationImpl {
|
|||||||
#endif
|
#endif
|
||||||
return internet_services;
|
return internet_services;
|
||||||
}),
|
}),
|
||||||
radio_services_([=]() { return new RadioServices(app, app); }),
|
radio_services_([app]() { return new RadioServices(app, app); }),
|
||||||
scrobbler_([=]() { return new AudioScrobbler(app, app); }),
|
scrobbler_([app]() { return new AudioScrobbler(app, app); }),
|
||||||
#ifdef HAVE_MOODBAR
|
#ifdef HAVE_MOODBAR
|
||||||
moodbar_loader_([=]() { return new MoodbarLoader(app, app); }),
|
moodbar_loader_([app]() { return new MoodbarLoader(app, app); }),
|
||||||
moodbar_controller_([=]() { return new MoodbarController(app, app); }),
|
moodbar_controller_([app]() { return new MoodbarController(app, app); }),
|
||||||
#endif
|
#endif
|
||||||
lastfm_import_([=]() { return new LastFMImport(app); })
|
lastfm_import_([app]() { return new LastFMImport(app); })
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Lazy<TagReaderClient> tag_reader_client_;
|
Lazy<TagReaderClient> tag_reader_client_;
|
||||||
Lazy<Database> database_;
|
Lazy<Database> database_;
|
||||||
Lazy<Appearance> appearance_;
|
|
||||||
Lazy<TaskManager> task_manager_;
|
Lazy<TaskManager> task_manager_;
|
||||||
Lazy<Player> player_;
|
Lazy<Player> player_;
|
||||||
Lazy<DeviceFinders> device_finders_;
|
Lazy<DeviceFinders> device_finders_;
|
||||||
@@ -317,7 +312,6 @@ void Application::ReloadSettings() { emit SettingsChanged(); }
|
|||||||
void Application::OpenSettingsDialogAtPage(SettingsDialog::Page page) { emit SettingsDialogRequested(page); }
|
void Application::OpenSettingsDialogAtPage(SettingsDialog::Page page) { emit SettingsDialogRequested(page); }
|
||||||
|
|
||||||
TagReaderClient *Application::tag_reader_client() const { return p_->tag_reader_client_.get(); }
|
TagReaderClient *Application::tag_reader_client() const { return p_->tag_reader_client_.get(); }
|
||||||
Appearance *Application::appearance() const { return p_->appearance_.get(); }
|
|
||||||
Database *Application::database() const { return p_->database_.get(); }
|
Database *Application::database() const { return p_->database_.get(); }
|
||||||
TaskManager *Application::task_manager() const { return p_->task_manager_.get(); }
|
TaskManager *Application::task_manager() const { return p_->task_manager_.get(); }
|
||||||
Player *Application::player() const { return p_->player_.get(); }
|
Player *Application::player() const { return p_->player_.get(); }
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user