@thelord/mcp-arr 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/arr-client.d.ts +239 -0
- package/dist/arr-client.d.ts.map +1 -1
- package/dist/arr-client.js +221 -0
- package/dist/arr-client.js.map +1 -1
- package/dist/index.js +1239 -249
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -572,6 +572,99 @@ if (clients.sonarr) {
|
|
|
572
572
|
},
|
|
573
573
|
required: ["tagId"],
|
|
574
574
|
},
|
|
575
|
+
}, {
|
|
576
|
+
name: "sonarr_get_history",
|
|
577
|
+
description: "Get Sonarr download/import history",
|
|
578
|
+
inputSchema: {
|
|
579
|
+
type: "object",
|
|
580
|
+
properties: {
|
|
581
|
+
page: {
|
|
582
|
+
type: "number",
|
|
583
|
+
description: "Page number (default: 1)",
|
|
584
|
+
},
|
|
585
|
+
pageSize: {
|
|
586
|
+
type: "number",
|
|
587
|
+
description: "Items per page (default: 20)",
|
|
588
|
+
},
|
|
589
|
+
seriesId: {
|
|
590
|
+
type: "number",
|
|
591
|
+
description: "Optional: filter to specific series ID",
|
|
592
|
+
},
|
|
593
|
+
},
|
|
594
|
+
required: [],
|
|
595
|
+
},
|
|
596
|
+
}, {
|
|
597
|
+
name: "sonarr_get_wanted",
|
|
598
|
+
description: "Get list of missing/wanted episodes",
|
|
599
|
+
inputSchema: {
|
|
600
|
+
type: "object",
|
|
601
|
+
properties: {
|
|
602
|
+
page: {
|
|
603
|
+
type: "number",
|
|
604
|
+
description: "Page number (default: 1)",
|
|
605
|
+
},
|
|
606
|
+
pageSize: {
|
|
607
|
+
type: "number",
|
|
608
|
+
description: "Items per page (default: 20)",
|
|
609
|
+
},
|
|
610
|
+
},
|
|
611
|
+
required: [],
|
|
612
|
+
},
|
|
613
|
+
}, {
|
|
614
|
+
name: "sonarr_get_cutoff_unmet",
|
|
615
|
+
description: "Get episodes with quality below cutoff that could be upgraded",
|
|
616
|
+
inputSchema: {
|
|
617
|
+
type: "object",
|
|
618
|
+
properties: {
|
|
619
|
+
page: {
|
|
620
|
+
type: "number",
|
|
621
|
+
description: "Page number (default: 1)",
|
|
622
|
+
},
|
|
623
|
+
pageSize: {
|
|
624
|
+
type: "number",
|
|
625
|
+
description: "Items per page (default: 20)",
|
|
626
|
+
},
|
|
627
|
+
},
|
|
628
|
+
required: [],
|
|
629
|
+
},
|
|
630
|
+
}, {
|
|
631
|
+
name: "sonarr_get_blocklist",
|
|
632
|
+
description: "Get blocklisted releases (releases that failed or were manually blocklisted)",
|
|
633
|
+
inputSchema: {
|
|
634
|
+
type: "object",
|
|
635
|
+
properties: {
|
|
636
|
+
page: {
|
|
637
|
+
type: "number",
|
|
638
|
+
description: "Page number (default: 1)",
|
|
639
|
+
},
|
|
640
|
+
pageSize: {
|
|
641
|
+
type: "number",
|
|
642
|
+
description: "Items per page (default: 20)",
|
|
643
|
+
},
|
|
644
|
+
},
|
|
645
|
+
required: [],
|
|
646
|
+
},
|
|
647
|
+
}, {
|
|
648
|
+
name: "sonarr_delete_blocklist_item",
|
|
649
|
+
description: "Remove an item from the blocklist",
|
|
650
|
+
inputSchema: {
|
|
651
|
+
type: "object",
|
|
652
|
+
properties: {
|
|
653
|
+
blocklistId: {
|
|
654
|
+
type: "number",
|
|
655
|
+
description: "Blocklist item ID to delete",
|
|
656
|
+
},
|
|
657
|
+
},
|
|
658
|
+
required: ["blocklistId"],
|
|
659
|
+
},
|
|
660
|
+
}, {
|
|
661
|
+
name: "sonarr_search_all_missing",
|
|
662
|
+
description: "Trigger a search for all missing episodes across all series",
|
|
663
|
+
inputSchema: {
|
|
664
|
+
type: "object",
|
|
665
|
+
properties: {},
|
|
666
|
+
required: [],
|
|
667
|
+
},
|
|
575
668
|
});
|
|
576
669
|
}
|
|
577
670
|
// Radarr tools
|
|
@@ -619,190 +712,526 @@ if (clients.radarr) {
|
|
|
619
712
|
required: [],
|
|
620
713
|
},
|
|
621
714
|
}, {
|
|
622
|
-
name: "
|
|
623
|
-
description: "
|
|
715
|
+
name: "radarr_add_movie",
|
|
716
|
+
description: "Add a new movie to Radarr",
|
|
624
717
|
inputSchema: {
|
|
625
718
|
type: "object",
|
|
626
719
|
properties: {
|
|
627
|
-
|
|
720
|
+
tmdbId: {
|
|
628
721
|
type: "number",
|
|
629
|
-
description: "
|
|
722
|
+
description: "TMDB ID for the movie (get from radarr_search)",
|
|
723
|
+
},
|
|
724
|
+
title: {
|
|
725
|
+
type: "string",
|
|
726
|
+
description: "Movie title",
|
|
727
|
+
},
|
|
728
|
+
qualityProfileId: {
|
|
729
|
+
type: "number",
|
|
730
|
+
description: "Quality profile ID (get from radarr_get_quality_profiles)",
|
|
731
|
+
},
|
|
732
|
+
rootFolderPath: {
|
|
733
|
+
type: "string",
|
|
734
|
+
description: "Root folder path (get from radarr_get_root_folders)",
|
|
735
|
+
},
|
|
736
|
+
monitored: {
|
|
737
|
+
type: "boolean",
|
|
738
|
+
description: "Monitor movie (default: true)",
|
|
739
|
+
},
|
|
740
|
+
minimumAvailability: {
|
|
741
|
+
type: "string",
|
|
742
|
+
description: "When to consider movie available: announced, inCinemas, released (default: released)",
|
|
743
|
+
},
|
|
744
|
+
tags: {
|
|
745
|
+
type: "array",
|
|
746
|
+
items: { type: "number" },
|
|
747
|
+
description: "Tag IDs to apply",
|
|
630
748
|
},
|
|
631
749
|
},
|
|
632
|
-
required: ["
|
|
750
|
+
required: ["tmdbId", "qualityProfileId", "rootFolderPath"],
|
|
633
751
|
},
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
if (clients.lidarr) {
|
|
638
|
-
TOOLS.push({
|
|
639
|
-
name: "lidarr_get_artists",
|
|
640
|
-
description: "Get all artists in Lidarr library",
|
|
752
|
+
}, {
|
|
753
|
+
name: "radarr_update_movie",
|
|
754
|
+
description: "Update an existing movie configuration (monitored, tags, quality profile, etc.)",
|
|
641
755
|
inputSchema: {
|
|
642
756
|
type: "object",
|
|
643
|
-
properties: {
|
|
644
|
-
|
|
757
|
+
properties: {
|
|
758
|
+
movieId: {
|
|
759
|
+
type: "number",
|
|
760
|
+
description: "Movie ID to update",
|
|
761
|
+
},
|
|
762
|
+
monitored: {
|
|
763
|
+
type: "boolean",
|
|
764
|
+
description: "Monitor movie",
|
|
765
|
+
},
|
|
766
|
+
qualityProfileId: {
|
|
767
|
+
type: "number",
|
|
768
|
+
description: "Quality profile ID",
|
|
769
|
+
},
|
|
770
|
+
minimumAvailability: {
|
|
771
|
+
type: "string",
|
|
772
|
+
description: "Minimum availability: announced, inCinemas, released",
|
|
773
|
+
},
|
|
774
|
+
tags: {
|
|
775
|
+
type: "array",
|
|
776
|
+
items: { type: "number" },
|
|
777
|
+
description: "Tag IDs to apply",
|
|
778
|
+
},
|
|
779
|
+
},
|
|
780
|
+
required: ["movieId"],
|
|
645
781
|
},
|
|
646
782
|
}, {
|
|
647
|
-
name: "
|
|
648
|
-
description: "
|
|
783
|
+
name: "radarr_delete_movie",
|
|
784
|
+
description: "Delete a movie from Radarr library. Optionally delete files and add to exclusion list.",
|
|
649
785
|
inputSchema: {
|
|
650
786
|
type: "object",
|
|
651
787
|
properties: {
|
|
652
|
-
|
|
653
|
-
type: "
|
|
654
|
-
description: "
|
|
788
|
+
movieId: {
|
|
789
|
+
type: "number",
|
|
790
|
+
description: "Movie ID to delete",
|
|
791
|
+
},
|
|
792
|
+
deleteFiles: {
|
|
793
|
+
type: "boolean",
|
|
794
|
+
description: "Delete all files for this movie (default: false)",
|
|
795
|
+
},
|
|
796
|
+
addImportExclusion: {
|
|
797
|
+
type: "boolean",
|
|
798
|
+
description: "Add movie to import exclusion list (default: false)",
|
|
655
799
|
},
|
|
656
800
|
},
|
|
657
|
-
required: ["
|
|
801
|
+
required: ["movieId"],
|
|
658
802
|
},
|
|
659
803
|
}, {
|
|
660
|
-
name: "
|
|
661
|
-
description: "
|
|
804
|
+
name: "radarr_search_movie",
|
|
805
|
+
description: "Trigger a search to download a movie that's already in your library",
|
|
662
806
|
inputSchema: {
|
|
663
807
|
type: "object",
|
|
664
|
-
properties: {
|
|
665
|
-
|
|
808
|
+
properties: {
|
|
809
|
+
movieId: {
|
|
810
|
+
type: "number",
|
|
811
|
+
description: "Movie ID to search for",
|
|
812
|
+
},
|
|
813
|
+
},
|
|
814
|
+
required: ["movieId"],
|
|
666
815
|
},
|
|
667
816
|
}, {
|
|
668
|
-
name: "
|
|
669
|
-
description: "Get
|
|
817
|
+
name: "radarr_get_history",
|
|
818
|
+
description: "Get Radarr download/import history",
|
|
670
819
|
inputSchema: {
|
|
671
820
|
type: "object",
|
|
672
821
|
properties: {
|
|
673
|
-
|
|
822
|
+
page: {
|
|
674
823
|
type: "number",
|
|
675
|
-
description: "
|
|
824
|
+
description: "Page number (default: 1)",
|
|
825
|
+
},
|
|
826
|
+
pageSize: {
|
|
827
|
+
type: "number",
|
|
828
|
+
description: "Items per page (default: 20)",
|
|
829
|
+
},
|
|
830
|
+
movieId: {
|
|
831
|
+
type: "number",
|
|
832
|
+
description: "Optional: filter to specific movie ID",
|
|
676
833
|
},
|
|
677
834
|
},
|
|
678
|
-
required: [
|
|
835
|
+
required: [],
|
|
679
836
|
},
|
|
680
837
|
}, {
|
|
681
|
-
name: "
|
|
682
|
-
description: "
|
|
838
|
+
name: "radarr_refresh_movie",
|
|
839
|
+
description: "Refresh movie metadata from TMDB",
|
|
683
840
|
inputSchema: {
|
|
684
841
|
type: "object",
|
|
685
842
|
properties: {
|
|
686
|
-
|
|
843
|
+
movieId: {
|
|
687
844
|
type: "number",
|
|
688
|
-
description: "
|
|
845
|
+
description: "Movie ID to refresh",
|
|
689
846
|
},
|
|
690
847
|
},
|
|
691
|
-
required: ["
|
|
848
|
+
required: ["movieId"],
|
|
692
849
|
},
|
|
693
850
|
}, {
|
|
694
|
-
name: "
|
|
695
|
-
description: "
|
|
851
|
+
name: "radarr_rescan_movie",
|
|
852
|
+
description: "Rescan movie disk for new/changed files",
|
|
696
853
|
inputSchema: {
|
|
697
854
|
type: "object",
|
|
698
855
|
properties: {
|
|
699
|
-
|
|
856
|
+
movieId: {
|
|
700
857
|
type: "number",
|
|
701
|
-
description: "
|
|
858
|
+
description: "Movie ID to rescan",
|
|
702
859
|
},
|
|
703
860
|
},
|
|
704
|
-
required: ["
|
|
861
|
+
required: ["movieId"],
|
|
705
862
|
},
|
|
706
863
|
}, {
|
|
707
|
-
name: "
|
|
708
|
-
description: "
|
|
864
|
+
name: "radarr_rename_movie",
|
|
865
|
+
description: "Rename movie files according to Radarr naming conventions",
|
|
709
866
|
inputSchema: {
|
|
710
867
|
type: "object",
|
|
711
868
|
properties: {
|
|
712
|
-
|
|
869
|
+
movieId: {
|
|
713
870
|
type: "number",
|
|
714
|
-
description: "
|
|
871
|
+
description: "Movie ID to rename",
|
|
715
872
|
},
|
|
716
873
|
},
|
|
717
|
-
required: [],
|
|
874
|
+
required: ["movieId"],
|
|
718
875
|
},
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
if (clients.readarr) {
|
|
723
|
-
TOOLS.push({
|
|
724
|
-
name: "readarr_get_authors",
|
|
725
|
-
description: "Get all authors in Readarr library",
|
|
876
|
+
}, {
|
|
877
|
+
name: "radarr_get_collections",
|
|
878
|
+
description: "Get all movie collections in Radarr",
|
|
726
879
|
inputSchema: {
|
|
727
880
|
type: "object",
|
|
728
881
|
properties: {},
|
|
729
882
|
required: [],
|
|
730
883
|
},
|
|
731
884
|
}, {
|
|
732
|
-
name: "
|
|
733
|
-
description: "
|
|
885
|
+
name: "radarr_update_collection",
|
|
886
|
+
description: "Update a collection (monitored status, quality profile, root folder)",
|
|
734
887
|
inputSchema: {
|
|
735
888
|
type: "object",
|
|
736
889
|
properties: {
|
|
737
|
-
|
|
890
|
+
collectionId: {
|
|
891
|
+
type: "number",
|
|
892
|
+
description: "Collection ID to update",
|
|
893
|
+
},
|
|
894
|
+
monitored: {
|
|
895
|
+
type: "boolean",
|
|
896
|
+
description: "Monitor collection (automatically add new movies)",
|
|
897
|
+
},
|
|
898
|
+
qualityProfileId: {
|
|
899
|
+
type: "number",
|
|
900
|
+
description: "Quality profile ID for new movies",
|
|
901
|
+
},
|
|
902
|
+
rootFolderPath: {
|
|
738
903
|
type: "string",
|
|
739
|
-
description: "
|
|
904
|
+
description: "Root folder for new movies",
|
|
905
|
+
},
|
|
906
|
+
searchOnAdd: {
|
|
907
|
+
type: "boolean",
|
|
908
|
+
description: "Search for movies when added from collection",
|
|
740
909
|
},
|
|
741
910
|
},
|
|
742
|
-
required: ["
|
|
911
|
+
required: ["collectionId"],
|
|
743
912
|
},
|
|
744
913
|
}, {
|
|
745
|
-
name: "
|
|
746
|
-
description: "Get
|
|
914
|
+
name: "radarr_get_movie_files",
|
|
915
|
+
description: "Get movie file details including quality, size, and media info",
|
|
747
916
|
inputSchema: {
|
|
748
917
|
type: "object",
|
|
749
|
-
properties: {
|
|
750
|
-
|
|
918
|
+
properties: {
|
|
919
|
+
movieId: {
|
|
920
|
+
type: "number",
|
|
921
|
+
description: "Movie ID to get files for",
|
|
922
|
+
},
|
|
923
|
+
},
|
|
924
|
+
required: ["movieId"],
|
|
751
925
|
},
|
|
752
926
|
}, {
|
|
753
|
-
name: "
|
|
754
|
-
description: "
|
|
927
|
+
name: "radarr_delete_movie_file",
|
|
928
|
+
description: "Delete a movie file. Useful for removing bad quality files to force re-download.",
|
|
755
929
|
inputSchema: {
|
|
756
930
|
type: "object",
|
|
757
931
|
properties: {
|
|
758
|
-
|
|
932
|
+
movieFileId: {
|
|
759
933
|
type: "number",
|
|
760
|
-
description: "
|
|
934
|
+
description: "Movie file ID to delete",
|
|
761
935
|
},
|
|
762
936
|
},
|
|
763
|
-
required: ["
|
|
937
|
+
required: ["movieFileId"],
|
|
764
938
|
},
|
|
765
939
|
}, {
|
|
766
|
-
name: "
|
|
767
|
-
description: "
|
|
940
|
+
name: "radarr_get_blocklist",
|
|
941
|
+
description: "Get blocklisted releases (releases that failed or were manually blocklisted)",
|
|
768
942
|
inputSchema: {
|
|
769
943
|
type: "object",
|
|
770
944
|
properties: {
|
|
771
|
-
|
|
772
|
-
type: "
|
|
773
|
-
|
|
774
|
-
|
|
945
|
+
page: {
|
|
946
|
+
type: "number",
|
|
947
|
+
description: "Page number (default: 1)",
|
|
948
|
+
},
|
|
949
|
+
pageSize: {
|
|
950
|
+
type: "number",
|
|
951
|
+
description: "Items per page (default: 20)",
|
|
775
952
|
},
|
|
776
953
|
},
|
|
777
|
-
required: [
|
|
954
|
+
required: [],
|
|
778
955
|
},
|
|
779
956
|
}, {
|
|
780
|
-
name: "
|
|
781
|
-
description: "
|
|
957
|
+
name: "radarr_delete_blocklist_item",
|
|
958
|
+
description: "Remove an item from the blocklist",
|
|
782
959
|
inputSchema: {
|
|
783
960
|
type: "object",
|
|
784
961
|
properties: {
|
|
785
|
-
|
|
962
|
+
blocklistId: {
|
|
786
963
|
type: "number",
|
|
787
|
-
description: "
|
|
964
|
+
description: "Blocklist item ID to delete",
|
|
788
965
|
},
|
|
789
966
|
},
|
|
790
|
-
required: ["
|
|
967
|
+
required: ["blocklistId"],
|
|
791
968
|
},
|
|
792
969
|
}, {
|
|
793
|
-
name: "
|
|
794
|
-
description: "Get
|
|
970
|
+
name: "radarr_get_extra_files",
|
|
971
|
+
description: "Get extra files for a movie (subtitles, nfo files, etc.)",
|
|
795
972
|
inputSchema: {
|
|
796
973
|
type: "object",
|
|
797
974
|
properties: {
|
|
798
|
-
|
|
975
|
+
movieId: {
|
|
799
976
|
type: "number",
|
|
800
|
-
description: "
|
|
977
|
+
description: "Movie ID to get extra files for",
|
|
801
978
|
},
|
|
802
979
|
},
|
|
803
|
-
required: [],
|
|
980
|
+
required: ["movieId"],
|
|
804
981
|
},
|
|
805
|
-
}
|
|
982
|
+
}, {
|
|
983
|
+
name: "radarr_get_credits",
|
|
984
|
+
description: "Get cast and crew credits for a movie",
|
|
985
|
+
inputSchema: {
|
|
986
|
+
type: "object",
|
|
987
|
+
properties: {
|
|
988
|
+
movieId: {
|
|
989
|
+
type: "number",
|
|
990
|
+
description: "Movie ID to get credits for",
|
|
991
|
+
},
|
|
992
|
+
},
|
|
993
|
+
required: ["movieId"],
|
|
994
|
+
},
|
|
995
|
+
}, {
|
|
996
|
+
name: "radarr_get_wanted",
|
|
997
|
+
description: "Get list of missing/wanted movies",
|
|
998
|
+
inputSchema: {
|
|
999
|
+
type: "object",
|
|
1000
|
+
properties: {
|
|
1001
|
+
page: {
|
|
1002
|
+
type: "number",
|
|
1003
|
+
description: "Page number (default: 1)",
|
|
1004
|
+
},
|
|
1005
|
+
pageSize: {
|
|
1006
|
+
type: "number",
|
|
1007
|
+
description: "Items per page (default: 20)",
|
|
1008
|
+
},
|
|
1009
|
+
},
|
|
1010
|
+
required: [],
|
|
1011
|
+
},
|
|
1012
|
+
}, {
|
|
1013
|
+
name: "radarr_search_missing",
|
|
1014
|
+
description: "Trigger a search for all missing/wanted movies",
|
|
1015
|
+
inputSchema: {
|
|
1016
|
+
type: "object",
|
|
1017
|
+
properties: {},
|
|
1018
|
+
required: [],
|
|
1019
|
+
},
|
|
1020
|
+
}, {
|
|
1021
|
+
name: "radarr_create_tag",
|
|
1022
|
+
description: "Create a new tag",
|
|
1023
|
+
inputSchema: {
|
|
1024
|
+
type: "object",
|
|
1025
|
+
properties: {
|
|
1026
|
+
label: {
|
|
1027
|
+
type: "string",
|
|
1028
|
+
description: "Tag label/name",
|
|
1029
|
+
},
|
|
1030
|
+
},
|
|
1031
|
+
required: ["label"],
|
|
1032
|
+
},
|
|
1033
|
+
}, {
|
|
1034
|
+
name: "radarr_update_tag",
|
|
1035
|
+
description: "Update a tag label",
|
|
1036
|
+
inputSchema: {
|
|
1037
|
+
type: "object",
|
|
1038
|
+
properties: {
|
|
1039
|
+
tagId: {
|
|
1040
|
+
type: "number",
|
|
1041
|
+
description: "Tag ID to update",
|
|
1042
|
+
},
|
|
1043
|
+
label: {
|
|
1044
|
+
type: "string",
|
|
1045
|
+
description: "New tag label",
|
|
1046
|
+
},
|
|
1047
|
+
},
|
|
1048
|
+
required: ["tagId", "label"],
|
|
1049
|
+
},
|
|
1050
|
+
}, {
|
|
1051
|
+
name: "radarr_delete_tag",
|
|
1052
|
+
description: "Delete a tag",
|
|
1053
|
+
inputSchema: {
|
|
1054
|
+
type: "object",
|
|
1055
|
+
properties: {
|
|
1056
|
+
tagId: {
|
|
1057
|
+
type: "number",
|
|
1058
|
+
description: "Tag ID to delete",
|
|
1059
|
+
},
|
|
1060
|
+
},
|
|
1061
|
+
required: ["tagId"],
|
|
1062
|
+
},
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
// Lidarr tools
|
|
1066
|
+
if (clients.lidarr) {
|
|
1067
|
+
TOOLS.push({
|
|
1068
|
+
name: "lidarr_get_artists",
|
|
1069
|
+
description: "Get all artists in Lidarr library",
|
|
1070
|
+
inputSchema: {
|
|
1071
|
+
type: "object",
|
|
1072
|
+
properties: {},
|
|
1073
|
+
required: [],
|
|
1074
|
+
},
|
|
1075
|
+
}, {
|
|
1076
|
+
name: "lidarr_search",
|
|
1077
|
+
description: "Search for artists to add to Lidarr",
|
|
1078
|
+
inputSchema: {
|
|
1079
|
+
type: "object",
|
|
1080
|
+
properties: {
|
|
1081
|
+
term: {
|
|
1082
|
+
type: "string",
|
|
1083
|
+
description: "Search term (artist name)",
|
|
1084
|
+
},
|
|
1085
|
+
},
|
|
1086
|
+
required: ["term"],
|
|
1087
|
+
},
|
|
1088
|
+
}, {
|
|
1089
|
+
name: "lidarr_get_queue",
|
|
1090
|
+
description: "Get Lidarr download queue",
|
|
1091
|
+
inputSchema: {
|
|
1092
|
+
type: "object",
|
|
1093
|
+
properties: {},
|
|
1094
|
+
required: [],
|
|
1095
|
+
},
|
|
1096
|
+
}, {
|
|
1097
|
+
name: "lidarr_get_albums",
|
|
1098
|
+
description: "Get albums for an artist in Lidarr. Shows which albums are available and which are missing.",
|
|
1099
|
+
inputSchema: {
|
|
1100
|
+
type: "object",
|
|
1101
|
+
properties: {
|
|
1102
|
+
artistId: {
|
|
1103
|
+
type: "number",
|
|
1104
|
+
description: "Artist ID to get albums for",
|
|
1105
|
+
},
|
|
1106
|
+
},
|
|
1107
|
+
required: ["artistId"],
|
|
1108
|
+
},
|
|
1109
|
+
}, {
|
|
1110
|
+
name: "lidarr_search_album",
|
|
1111
|
+
description: "Trigger a search for a specific album to download",
|
|
1112
|
+
inputSchema: {
|
|
1113
|
+
type: "object",
|
|
1114
|
+
properties: {
|
|
1115
|
+
albumId: {
|
|
1116
|
+
type: "number",
|
|
1117
|
+
description: "Album ID to search for",
|
|
1118
|
+
},
|
|
1119
|
+
},
|
|
1120
|
+
required: ["albumId"],
|
|
1121
|
+
},
|
|
1122
|
+
}, {
|
|
1123
|
+
name: "lidarr_search_missing",
|
|
1124
|
+
description: "Trigger a search for all missing albums for an artist",
|
|
1125
|
+
inputSchema: {
|
|
1126
|
+
type: "object",
|
|
1127
|
+
properties: {
|
|
1128
|
+
artistId: {
|
|
1129
|
+
type: "number",
|
|
1130
|
+
description: "Artist ID to search missing albums for",
|
|
1131
|
+
},
|
|
1132
|
+
},
|
|
1133
|
+
required: ["artistId"],
|
|
1134
|
+
},
|
|
1135
|
+
}, {
|
|
1136
|
+
name: "lidarr_get_calendar",
|
|
1137
|
+
description: "Get upcoming album releases from Lidarr",
|
|
1138
|
+
inputSchema: {
|
|
1139
|
+
type: "object",
|
|
1140
|
+
properties: {
|
|
1141
|
+
days: {
|
|
1142
|
+
type: "number",
|
|
1143
|
+
description: "Number of days to look ahead (default: 30)",
|
|
1144
|
+
},
|
|
1145
|
+
},
|
|
1146
|
+
required: [],
|
|
1147
|
+
},
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
// Readarr tools
|
|
1151
|
+
if (clients.readarr) {
|
|
1152
|
+
TOOLS.push({
|
|
1153
|
+
name: "readarr_get_authors",
|
|
1154
|
+
description: "Get all authors in Readarr library",
|
|
1155
|
+
inputSchema: {
|
|
1156
|
+
type: "object",
|
|
1157
|
+
properties: {},
|
|
1158
|
+
required: [],
|
|
1159
|
+
},
|
|
1160
|
+
}, {
|
|
1161
|
+
name: "readarr_search",
|
|
1162
|
+
description: "Search for authors to add to Readarr",
|
|
1163
|
+
inputSchema: {
|
|
1164
|
+
type: "object",
|
|
1165
|
+
properties: {
|
|
1166
|
+
term: {
|
|
1167
|
+
type: "string",
|
|
1168
|
+
description: "Search term (author name)",
|
|
1169
|
+
},
|
|
1170
|
+
},
|
|
1171
|
+
required: ["term"],
|
|
1172
|
+
},
|
|
1173
|
+
}, {
|
|
1174
|
+
name: "readarr_get_queue",
|
|
1175
|
+
description: "Get Readarr download queue",
|
|
1176
|
+
inputSchema: {
|
|
1177
|
+
type: "object",
|
|
1178
|
+
properties: {},
|
|
1179
|
+
required: [],
|
|
1180
|
+
},
|
|
1181
|
+
}, {
|
|
1182
|
+
name: "readarr_get_books",
|
|
1183
|
+
description: "Get books for an author in Readarr. Shows which books are available and which are missing.",
|
|
1184
|
+
inputSchema: {
|
|
1185
|
+
type: "object",
|
|
1186
|
+
properties: {
|
|
1187
|
+
authorId: {
|
|
1188
|
+
type: "number",
|
|
1189
|
+
description: "Author ID to get books for",
|
|
1190
|
+
},
|
|
1191
|
+
},
|
|
1192
|
+
required: ["authorId"],
|
|
1193
|
+
},
|
|
1194
|
+
}, {
|
|
1195
|
+
name: "readarr_search_book",
|
|
1196
|
+
description: "Trigger a search for a specific book to download",
|
|
1197
|
+
inputSchema: {
|
|
1198
|
+
type: "object",
|
|
1199
|
+
properties: {
|
|
1200
|
+
bookIds: {
|
|
1201
|
+
type: "array",
|
|
1202
|
+
items: { type: "number" },
|
|
1203
|
+
description: "Book ID(s) to search for",
|
|
1204
|
+
},
|
|
1205
|
+
},
|
|
1206
|
+
required: ["bookIds"],
|
|
1207
|
+
},
|
|
1208
|
+
}, {
|
|
1209
|
+
name: "readarr_search_missing",
|
|
1210
|
+
description: "Trigger a search for all missing books for an author",
|
|
1211
|
+
inputSchema: {
|
|
1212
|
+
type: "object",
|
|
1213
|
+
properties: {
|
|
1214
|
+
authorId: {
|
|
1215
|
+
type: "number",
|
|
1216
|
+
description: "Author ID to search missing books for",
|
|
1217
|
+
},
|
|
1218
|
+
},
|
|
1219
|
+
required: ["authorId"],
|
|
1220
|
+
},
|
|
1221
|
+
}, {
|
|
1222
|
+
name: "readarr_get_calendar",
|
|
1223
|
+
description: "Get upcoming book releases from Readarr",
|
|
1224
|
+
inputSchema: {
|
|
1225
|
+
type: "object",
|
|
1226
|
+
properties: {
|
|
1227
|
+
days: {
|
|
1228
|
+
type: "number",
|
|
1229
|
+
description: "Number of days to look ahead (default: 30)",
|
|
1230
|
+
},
|
|
1231
|
+
},
|
|
1232
|
+
required: [],
|
|
1233
|
+
},
|
|
1234
|
+
});
|
|
806
1235
|
}
|
|
807
1236
|
// Prowlarr tools
|
|
808
1237
|
if (clients.prowlarr) {
|
|
@@ -1500,362 +1929,923 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1500
1929
|
}],
|
|
1501
1930
|
};
|
|
1502
1931
|
}
|
|
1503
|
-
case "sonarr_update_series": {
|
|
1504
|
-
if (!clients.sonarr)
|
|
1505
|
-
throw new Error("Sonarr not configured");
|
|
1506
|
-
const { seriesId, ...updates } = args;
|
|
1507
|
-
const series = await clients.sonarr.updateSeries(seriesId, updates);
|
|
1932
|
+
case "sonarr_update_series": {
|
|
1933
|
+
if (!clients.sonarr)
|
|
1934
|
+
throw new Error("Sonarr not configured");
|
|
1935
|
+
const { seriesId, ...updates } = args;
|
|
1936
|
+
const series = await clients.sonarr.updateSeries(seriesId, updates);
|
|
1937
|
+
return {
|
|
1938
|
+
content: [{
|
|
1939
|
+
type: "text",
|
|
1940
|
+
text: JSON.stringify({
|
|
1941
|
+
success: true,
|
|
1942
|
+
message: `Series '${series.title}' updated`,
|
|
1943
|
+
seriesId: series.id,
|
|
1944
|
+
updates: Object.keys(updates),
|
|
1945
|
+
}, null, 2),
|
|
1946
|
+
}],
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
case "sonarr_delete_series": {
|
|
1950
|
+
if (!clients.sonarr)
|
|
1951
|
+
throw new Error("Sonarr not configured");
|
|
1952
|
+
const { seriesId, deleteFiles = false, addImportListExclusion = false } = args;
|
|
1953
|
+
await clients.sonarr.deleteSeries(seriesId, deleteFiles, addImportListExclusion);
|
|
1954
|
+
return {
|
|
1955
|
+
content: [{
|
|
1956
|
+
type: "text",
|
|
1957
|
+
text: JSON.stringify({
|
|
1958
|
+
success: true,
|
|
1959
|
+
message: `Series deleted (files: ${deleteFiles}, exclude: ${addImportListExclusion})`,
|
|
1960
|
+
}, null, 2),
|
|
1961
|
+
}],
|
|
1962
|
+
};
|
|
1963
|
+
}
|
|
1964
|
+
case "sonarr_update_episode": {
|
|
1965
|
+
if (!clients.sonarr)
|
|
1966
|
+
throw new Error("Sonarr not configured");
|
|
1967
|
+
const { episodeId, monitored } = args;
|
|
1968
|
+
const episode = await clients.sonarr.updateEpisode(episodeId, { monitored });
|
|
1969
|
+
return {
|
|
1970
|
+
content: [{
|
|
1971
|
+
type: "text",
|
|
1972
|
+
text: JSON.stringify({
|
|
1973
|
+
success: true,
|
|
1974
|
+
message: `Episode ${episodeId} ${monitored ? 'monitored' : 'unmonitored'}`,
|
|
1975
|
+
episodeId: episode.id,
|
|
1976
|
+
monitored: episode.monitored,
|
|
1977
|
+
}, null, 2),
|
|
1978
|
+
}],
|
|
1979
|
+
};
|
|
1980
|
+
}
|
|
1981
|
+
case "sonarr_delete_episode_file": {
|
|
1982
|
+
if (!clients.sonarr)
|
|
1983
|
+
throw new Error("Sonarr not configured");
|
|
1984
|
+
const { episodeFileId } = args;
|
|
1985
|
+
await clients.sonarr.deleteEpisodeFile(episodeFileId);
|
|
1986
|
+
return {
|
|
1987
|
+
content: [{
|
|
1988
|
+
type: "text",
|
|
1989
|
+
text: JSON.stringify({
|
|
1990
|
+
success: true,
|
|
1991
|
+
message: `Episode file ${episodeFileId} deleted`,
|
|
1992
|
+
}, null, 2),
|
|
1993
|
+
}],
|
|
1994
|
+
};
|
|
1995
|
+
}
|
|
1996
|
+
case "sonarr_refresh_series": {
|
|
1997
|
+
if (!clients.sonarr)
|
|
1998
|
+
throw new Error("Sonarr not configured");
|
|
1999
|
+
const { seriesId } = args;
|
|
2000
|
+
const result = await clients.sonarr.refreshSeries(seriesId);
|
|
2001
|
+
return {
|
|
2002
|
+
content: [{
|
|
2003
|
+
type: "text",
|
|
2004
|
+
text: JSON.stringify({
|
|
2005
|
+
success: true,
|
|
2006
|
+
message: `Series ${seriesId} metadata refresh triggered`,
|
|
2007
|
+
commandId: result.id,
|
|
2008
|
+
}, null, 2),
|
|
2009
|
+
}],
|
|
2010
|
+
};
|
|
2011
|
+
}
|
|
2012
|
+
case "sonarr_rescan_series": {
|
|
2013
|
+
if (!clients.sonarr)
|
|
2014
|
+
throw new Error("Sonarr not configured");
|
|
2015
|
+
const { seriesId } = args;
|
|
2016
|
+
const result = await clients.sonarr.rescanSeries(seriesId);
|
|
2017
|
+
return {
|
|
2018
|
+
content: [{
|
|
2019
|
+
type: "text",
|
|
2020
|
+
text: JSON.stringify({
|
|
2021
|
+
success: true,
|
|
2022
|
+
message: `Series ${seriesId} disk rescan triggered`,
|
|
2023
|
+
commandId: result.id,
|
|
2024
|
+
}, null, 2),
|
|
2025
|
+
}],
|
|
2026
|
+
};
|
|
2027
|
+
}
|
|
2028
|
+
case "sonarr_rename_series": {
|
|
2029
|
+
if (!clients.sonarr)
|
|
2030
|
+
throw new Error("Sonarr not configured");
|
|
2031
|
+
const { seriesId } = args;
|
|
2032
|
+
const result = await clients.sonarr.renameSeries(seriesId);
|
|
2033
|
+
return {
|
|
2034
|
+
content: [{
|
|
2035
|
+
type: "text",
|
|
2036
|
+
text: JSON.stringify({
|
|
2037
|
+
success: true,
|
|
2038
|
+
message: `Series ${seriesId} files will be renamed`,
|
|
2039
|
+
commandId: result.id,
|
|
2040
|
+
}, null, 2),
|
|
2041
|
+
}],
|
|
2042
|
+
};
|
|
2043
|
+
}
|
|
2044
|
+
case "sonarr_rename_episodes": {
|
|
2045
|
+
if (!clients.sonarr)
|
|
2046
|
+
throw new Error("Sonarr not configured");
|
|
2047
|
+
const { seriesId } = args;
|
|
2048
|
+
const result = await clients.sonarr.renameEpisodes(seriesId);
|
|
2049
|
+
return {
|
|
2050
|
+
content: [{
|
|
2051
|
+
type: "text",
|
|
2052
|
+
text: JSON.stringify({
|
|
2053
|
+
success: true,
|
|
2054
|
+
message: `All episodes for series ${seriesId} will be renamed`,
|
|
2055
|
+
commandId: result.id,
|
|
2056
|
+
}, null, 2),
|
|
2057
|
+
}],
|
|
2058
|
+
};
|
|
2059
|
+
}
|
|
2060
|
+
case "sonarr_get_releases": {
|
|
2061
|
+
if (!clients.sonarr)
|
|
2062
|
+
throw new Error("Sonarr not configured");
|
|
2063
|
+
const { seriesId, page = 1, pageSize = 10 } = args;
|
|
2064
|
+
const releases = await clients.sonarr.getReleases(seriesId, page, pageSize);
|
|
2065
|
+
return {
|
|
2066
|
+
content: [{
|
|
2067
|
+
type: "text",
|
|
2068
|
+
text: JSON.stringify({
|
|
2069
|
+
totalRecords: releases.length,
|
|
2070
|
+
page,
|
|
2071
|
+
pageSize,
|
|
2072
|
+
releases: releases.map((r) => ({
|
|
2073
|
+
guid: r.guid,
|
|
2074
|
+
title: r.title,
|
|
2075
|
+
indexer: r.indexer,
|
|
2076
|
+
quality: r.quality,
|
|
2077
|
+
size: formatBytes(r.size),
|
|
2078
|
+
age: r.age,
|
|
2079
|
+
ageHours: r.ageHours,
|
|
2080
|
+
rejected: r.rejected,
|
|
2081
|
+
rejectionReason: r.rejectionReason,
|
|
2082
|
+
publishedDate: r.publishedDate,
|
|
2083
|
+
})),
|
|
2084
|
+
}, null, 2),
|
|
2085
|
+
}],
|
|
2086
|
+
};
|
|
2087
|
+
}
|
|
2088
|
+
case "sonarr_delete_release": {
|
|
2089
|
+
if (!clients.sonarr)
|
|
2090
|
+
throw new Error("Sonarr not configured");
|
|
2091
|
+
const { guid } = args;
|
|
2092
|
+
await clients.sonarr.deleteRelease(guid);
|
|
2093
|
+
return {
|
|
2094
|
+
content: [{
|
|
2095
|
+
type: "text",
|
|
2096
|
+
text: JSON.stringify({
|
|
2097
|
+
success: true,
|
|
2098
|
+
message: `Release ${guid} deleted from history`,
|
|
2099
|
+
}, null, 2),
|
|
2100
|
+
}],
|
|
2101
|
+
};
|
|
2102
|
+
}
|
|
2103
|
+
case "sonarr_create_release_profile": {
|
|
2104
|
+
if (!clients.sonarr)
|
|
2105
|
+
throw new Error("Sonarr not configured");
|
|
2106
|
+
const profile = await clients.sonarr.createReleaseProfile(args);
|
|
2107
|
+
return {
|
|
2108
|
+
content: [{
|
|
2109
|
+
type: "text",
|
|
2110
|
+
text: JSON.stringify({
|
|
2111
|
+
success: true,
|
|
2112
|
+
message: `Release profile '${profile.name}' created`,
|
|
2113
|
+
profileId: profile.id,
|
|
2114
|
+
profile,
|
|
2115
|
+
}, null, 2),
|
|
2116
|
+
}],
|
|
2117
|
+
};
|
|
2118
|
+
}
|
|
2119
|
+
case "sonarr_update_release_profile": {
|
|
2120
|
+
if (!clients.sonarr)
|
|
2121
|
+
throw new Error("Sonarr not configured");
|
|
2122
|
+
const { profileId, ...updates } = args;
|
|
2123
|
+
const profile = await clients.sonarr.updateReleaseProfile(profileId, updates);
|
|
2124
|
+
return {
|
|
2125
|
+
content: [{
|
|
2126
|
+
type: "text",
|
|
2127
|
+
text: JSON.stringify({
|
|
2128
|
+
success: true,
|
|
2129
|
+
message: `Release profile ${profileId} updated`,
|
|
2130
|
+
profileId: profile.id,
|
|
2131
|
+
profile,
|
|
2132
|
+
}, null, 2),
|
|
2133
|
+
}],
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2136
|
+
case "sonarr_delete_release_profile": {
|
|
2137
|
+
if (!clients.sonarr)
|
|
2138
|
+
throw new Error("Sonarr not configured");
|
|
2139
|
+
const { profileId } = args;
|
|
2140
|
+
await clients.sonarr.deleteReleaseProfile(profileId);
|
|
2141
|
+
return {
|
|
2142
|
+
content: [{
|
|
2143
|
+
type: "text",
|
|
2144
|
+
text: JSON.stringify({
|
|
2145
|
+
success: true,
|
|
2146
|
+
message: `Release profile ${profileId} deleted`,
|
|
2147
|
+
}, null, 2),
|
|
2148
|
+
}],
|
|
2149
|
+
};
|
|
2150
|
+
}
|
|
2151
|
+
case "sonarr_create_tag": {
|
|
2152
|
+
if (!clients.sonarr)
|
|
2153
|
+
throw new Error("Sonarr not configured");
|
|
2154
|
+
const { label } = args;
|
|
2155
|
+
const tag = await clients.sonarr.createTag(label);
|
|
2156
|
+
return {
|
|
2157
|
+
content: [{
|
|
2158
|
+
type: "text",
|
|
2159
|
+
text: JSON.stringify({
|
|
2160
|
+
success: true,
|
|
2161
|
+
message: `Tag '${label}' created`,
|
|
2162
|
+
tagId: tag.id,
|
|
2163
|
+
tag,
|
|
2164
|
+
}, null, 2),
|
|
2165
|
+
}],
|
|
2166
|
+
};
|
|
2167
|
+
}
|
|
2168
|
+
case "sonarr_update_tag": {
|
|
2169
|
+
if (!clients.sonarr)
|
|
2170
|
+
throw new Error("Sonarr not configured");
|
|
2171
|
+
const { tagId, label } = args;
|
|
2172
|
+
const tag = await clients.sonarr.updateTag(tagId, label);
|
|
2173
|
+
return {
|
|
2174
|
+
content: [{
|
|
2175
|
+
type: "text",
|
|
2176
|
+
text: JSON.stringify({
|
|
2177
|
+
success: true,
|
|
2178
|
+
message: `Tag ${tagId} updated to '${label}'`,
|
|
2179
|
+
tagId: tag.id,
|
|
2180
|
+
tag,
|
|
2181
|
+
}, null, 2),
|
|
2182
|
+
}],
|
|
2183
|
+
};
|
|
2184
|
+
}
|
|
2185
|
+
case "sonarr_delete_tag": {
|
|
2186
|
+
if (!clients.sonarr)
|
|
2187
|
+
throw new Error("Sonarr not configured");
|
|
2188
|
+
const { tagId } = args;
|
|
2189
|
+
await clients.sonarr.deleteTag(tagId);
|
|
2190
|
+
return {
|
|
2191
|
+
content: [{
|
|
2192
|
+
type: "text",
|
|
2193
|
+
text: JSON.stringify({
|
|
2194
|
+
success: true,
|
|
2195
|
+
message: `Tag ${tagId} deleted`,
|
|
2196
|
+
}, null, 2),
|
|
2197
|
+
}],
|
|
2198
|
+
};
|
|
2199
|
+
}
|
|
2200
|
+
case "sonarr_get_history": {
|
|
2201
|
+
if (!clients.sonarr)
|
|
2202
|
+
throw new Error("Sonarr not configured");
|
|
2203
|
+
const { page = 1, pageSize = 20, seriesId } = args;
|
|
2204
|
+
if (seriesId) {
|
|
2205
|
+
const history = await clients.sonarr.getSeriesHistory(seriesId);
|
|
2206
|
+
return {
|
|
2207
|
+
content: [{
|
|
2208
|
+
type: "text",
|
|
2209
|
+
text: JSON.stringify({
|
|
2210
|
+
seriesId,
|
|
2211
|
+
count: history.length,
|
|
2212
|
+
records: history.map((h) => ({
|
|
2213
|
+
id: h.id,
|
|
2214
|
+
date: h.date,
|
|
2215
|
+
eventType: h.eventType,
|
|
2216
|
+
sourceTitle: h.sourceTitle,
|
|
2217
|
+
quality: h.quality?.quality?.name,
|
|
2218
|
+
episodeId: h.episodeId,
|
|
2219
|
+
})),
|
|
2220
|
+
}, null, 2),
|
|
2221
|
+
}],
|
|
2222
|
+
};
|
|
2223
|
+
}
|
|
2224
|
+
const history = await clients.sonarr.getHistory(page, pageSize);
|
|
2225
|
+
return {
|
|
2226
|
+
content: [{
|
|
2227
|
+
type: "text",
|
|
2228
|
+
text: JSON.stringify({
|
|
2229
|
+
page,
|
|
2230
|
+
pageSize,
|
|
2231
|
+
totalRecords: history.totalRecords,
|
|
2232
|
+
records: history.records.map((h) => ({
|
|
2233
|
+
id: h.id,
|
|
2234
|
+
seriesId: h.seriesId,
|
|
2235
|
+
episodeId: h.episodeId,
|
|
2236
|
+
date: h.date,
|
|
2237
|
+
eventType: h.eventType,
|
|
2238
|
+
sourceTitle: h.sourceTitle,
|
|
2239
|
+
quality: h.quality?.quality?.name,
|
|
2240
|
+
})),
|
|
2241
|
+
}, null, 2),
|
|
2242
|
+
}],
|
|
2243
|
+
};
|
|
2244
|
+
}
|
|
2245
|
+
case "sonarr_get_wanted": {
|
|
2246
|
+
if (!clients.sonarr)
|
|
2247
|
+
throw new Error("Sonarr not configured");
|
|
2248
|
+
const { page = 1, pageSize = 20 } = args;
|
|
2249
|
+
const wanted = await clients.sonarr.getWanted(page, pageSize);
|
|
2250
|
+
return {
|
|
2251
|
+
content: [{
|
|
2252
|
+
type: "text",
|
|
2253
|
+
text: JSON.stringify({
|
|
2254
|
+
page,
|
|
2255
|
+
pageSize,
|
|
2256
|
+
totalRecords: wanted.totalRecords,
|
|
2257
|
+
episodes: wanted.records.map((e) => ({
|
|
2258
|
+
id: e.id,
|
|
2259
|
+
seriesId: e.seriesId,
|
|
2260
|
+
seasonNumber: e.seasonNumber,
|
|
2261
|
+
episodeNumber: e.episodeNumber,
|
|
2262
|
+
title: e.title,
|
|
2263
|
+
airDate: e.airDate,
|
|
2264
|
+
monitored: e.monitored,
|
|
2265
|
+
})),
|
|
2266
|
+
}, null, 2),
|
|
2267
|
+
}],
|
|
2268
|
+
};
|
|
2269
|
+
}
|
|
2270
|
+
case "sonarr_get_cutoff_unmet": {
|
|
2271
|
+
if (!clients.sonarr)
|
|
2272
|
+
throw new Error("Sonarr not configured");
|
|
2273
|
+
const { page = 1, pageSize = 20 } = args;
|
|
2274
|
+
const cutoff = await clients.sonarr.getCutoffUnmet(page, pageSize);
|
|
2275
|
+
return {
|
|
2276
|
+
content: [{
|
|
2277
|
+
type: "text",
|
|
2278
|
+
text: JSON.stringify({
|
|
2279
|
+
page,
|
|
2280
|
+
pageSize,
|
|
2281
|
+
totalRecords: cutoff.totalRecords,
|
|
2282
|
+
episodes: cutoff.records.map((e) => ({
|
|
2283
|
+
id: e.id,
|
|
2284
|
+
seriesId: e.seriesId,
|
|
2285
|
+
seasonNumber: e.seasonNumber,
|
|
2286
|
+
episodeNumber: e.episodeNumber,
|
|
2287
|
+
title: e.title,
|
|
2288
|
+
currentQuality: e.episodeFile?.quality?.quality?.name,
|
|
2289
|
+
})),
|
|
2290
|
+
}, null, 2),
|
|
2291
|
+
}],
|
|
2292
|
+
};
|
|
2293
|
+
}
|
|
2294
|
+
case "sonarr_get_blocklist": {
|
|
2295
|
+
if (!clients.sonarr)
|
|
2296
|
+
throw new Error("Sonarr not configured");
|
|
2297
|
+
const { page = 1, pageSize = 20 } = args;
|
|
2298
|
+
const blocklist = await clients.sonarr.getBlocklist(page, pageSize);
|
|
2299
|
+
return {
|
|
2300
|
+
content: [{
|
|
2301
|
+
type: "text",
|
|
2302
|
+
text: JSON.stringify({
|
|
2303
|
+
page,
|
|
2304
|
+
pageSize,
|
|
2305
|
+
totalRecords: blocklist.totalRecords,
|
|
2306
|
+
records: blocklist.records.map((b) => ({
|
|
2307
|
+
id: b.id,
|
|
2308
|
+
seriesId: b.seriesId,
|
|
2309
|
+
sourceTitle: b.sourceTitle,
|
|
2310
|
+
date: b.date,
|
|
2311
|
+
protocol: b.protocol,
|
|
2312
|
+
indexer: b.indexer,
|
|
2313
|
+
message: b.message,
|
|
2314
|
+
})),
|
|
2315
|
+
}, null, 2),
|
|
2316
|
+
}],
|
|
2317
|
+
};
|
|
2318
|
+
}
|
|
2319
|
+
case "sonarr_delete_blocklist_item": {
|
|
2320
|
+
if (!clients.sonarr)
|
|
2321
|
+
throw new Error("Sonarr not configured");
|
|
2322
|
+
const { blocklistId } = args;
|
|
2323
|
+
await clients.sonarr.deleteBlocklistItem(blocklistId);
|
|
2324
|
+
return {
|
|
2325
|
+
content: [{
|
|
2326
|
+
type: "text",
|
|
2327
|
+
text: JSON.stringify({
|
|
2328
|
+
success: true,
|
|
2329
|
+
message: `Blocklist item ${blocklistId} deleted`,
|
|
2330
|
+
}, null, 2),
|
|
2331
|
+
}],
|
|
2332
|
+
};
|
|
2333
|
+
}
|
|
2334
|
+
case "sonarr_search_all_missing": {
|
|
2335
|
+
if (!clients.sonarr)
|
|
2336
|
+
throw new Error("Sonarr not configured");
|
|
2337
|
+
const result = await clients.sonarr.searchAllMissing();
|
|
2338
|
+
return {
|
|
2339
|
+
content: [{
|
|
2340
|
+
type: "text",
|
|
2341
|
+
text: JSON.stringify({
|
|
2342
|
+
success: true,
|
|
2343
|
+
message: 'Search triggered for all missing episodes',
|
|
2344
|
+
commandId: result.id,
|
|
2345
|
+
}, null, 2),
|
|
2346
|
+
}],
|
|
2347
|
+
};
|
|
2348
|
+
}
|
|
2349
|
+
// Radarr handlers
|
|
2350
|
+
case "radarr_get_movies": {
|
|
2351
|
+
if (!clients.radarr)
|
|
2352
|
+
throw new Error("Radarr not configured");
|
|
2353
|
+
const movies = await clients.radarr.getMovies();
|
|
2354
|
+
return {
|
|
2355
|
+
content: [{
|
|
2356
|
+
type: "text",
|
|
2357
|
+
text: JSON.stringify({
|
|
2358
|
+
count: movies.length,
|
|
2359
|
+
movies: movies.map(m => ({
|
|
2360
|
+
id: m.id,
|
|
2361
|
+
title: m.title,
|
|
2362
|
+
year: m.year,
|
|
2363
|
+
status: m.status,
|
|
2364
|
+
hasFile: m.hasFile,
|
|
2365
|
+
sizeOnDisk: formatBytes(m.sizeOnDisk),
|
|
2366
|
+
monitored: m.monitored,
|
|
2367
|
+
studio: m.studio,
|
|
2368
|
+
})),
|
|
2369
|
+
}, null, 2),
|
|
2370
|
+
}],
|
|
2371
|
+
};
|
|
2372
|
+
}
|
|
2373
|
+
case "radarr_search": {
|
|
2374
|
+
if (!clients.radarr)
|
|
2375
|
+
throw new Error("Radarr not configured");
|
|
2376
|
+
const term = args.term;
|
|
2377
|
+
const results = await clients.radarr.searchMovies(term);
|
|
2378
|
+
return {
|
|
2379
|
+
content: [{
|
|
2380
|
+
type: "text",
|
|
2381
|
+
text: JSON.stringify({
|
|
2382
|
+
count: results.length,
|
|
2383
|
+
results: results.slice(0, 10).map(r => ({
|
|
2384
|
+
title: r.title,
|
|
2385
|
+
year: r.year,
|
|
2386
|
+
tmdbId: r.tmdbId,
|
|
2387
|
+
imdbId: r.imdbId,
|
|
2388
|
+
overview: r.overview?.substring(0, 200) + (r.overview && r.overview.length > 200 ? '...' : ''),
|
|
2389
|
+
})),
|
|
2390
|
+
}, null, 2),
|
|
2391
|
+
}],
|
|
2392
|
+
};
|
|
2393
|
+
}
|
|
2394
|
+
case "radarr_get_queue": {
|
|
2395
|
+
if (!clients.radarr)
|
|
2396
|
+
throw new Error("Radarr not configured");
|
|
2397
|
+
const queue = await clients.radarr.getQueue();
|
|
2398
|
+
return {
|
|
2399
|
+
content: [{
|
|
2400
|
+
type: "text",
|
|
2401
|
+
text: JSON.stringify({
|
|
2402
|
+
totalRecords: queue.totalRecords,
|
|
2403
|
+
items: queue.records.map(q => ({
|
|
2404
|
+
title: q.title,
|
|
2405
|
+
status: q.status,
|
|
2406
|
+
progress: ((1 - q.sizeleft / q.size) * 100).toFixed(1) + '%',
|
|
2407
|
+
timeLeft: q.timeleft,
|
|
2408
|
+
downloadClient: q.downloadClient,
|
|
2409
|
+
})),
|
|
2410
|
+
}, null, 2),
|
|
2411
|
+
}],
|
|
2412
|
+
};
|
|
2413
|
+
}
|
|
2414
|
+
case "radarr_get_calendar": {
|
|
2415
|
+
if (!clients.radarr)
|
|
2416
|
+
throw new Error("Radarr not configured");
|
|
2417
|
+
const days = args?.days || 30;
|
|
2418
|
+
const start = new Date().toISOString().split('T')[0];
|
|
2419
|
+
const end = new Date(Date.now() + days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
2420
|
+
const calendar = await clients.radarr.getCalendar(start, end);
|
|
2421
|
+
return {
|
|
2422
|
+
content: [{ type: "text", text: JSON.stringify(calendar, null, 2) }],
|
|
2423
|
+
};
|
|
2424
|
+
}
|
|
2425
|
+
case "radarr_search_movie": {
|
|
2426
|
+
if (!clients.radarr)
|
|
2427
|
+
throw new Error("Radarr not configured");
|
|
2428
|
+
const movieId = args.movieId;
|
|
2429
|
+
const result = await clients.radarr.searchMovie(movieId);
|
|
1508
2430
|
return {
|
|
1509
2431
|
content: [{
|
|
1510
2432
|
type: "text",
|
|
1511
2433
|
text: JSON.stringify({
|
|
1512
2434
|
success: true,
|
|
1513
|
-
message: `
|
|
1514
|
-
|
|
1515
|
-
updates: Object.keys(updates),
|
|
2435
|
+
message: `Search triggered for movie`,
|
|
2436
|
+
commandId: result.id,
|
|
1516
2437
|
}, null, 2),
|
|
1517
2438
|
}],
|
|
1518
2439
|
};
|
|
1519
2440
|
}
|
|
1520
|
-
case "
|
|
1521
|
-
if (!clients.
|
|
1522
|
-
throw new Error("
|
|
1523
|
-
const {
|
|
1524
|
-
await clients.
|
|
2441
|
+
case "radarr_add_movie": {
|
|
2442
|
+
if (!clients.radarr)
|
|
2443
|
+
throw new Error("Radarr not configured");
|
|
2444
|
+
const { tmdbId, title, qualityProfileId, rootFolderPath, monitored, minimumAvailability, tags } = args;
|
|
2445
|
+
const movie = await clients.radarr.addMovie({
|
|
2446
|
+
tmdbId,
|
|
2447
|
+
title,
|
|
2448
|
+
qualityProfileId,
|
|
2449
|
+
rootFolderPath,
|
|
2450
|
+
monitored,
|
|
2451
|
+
minimumAvailability: minimumAvailability || 'released',
|
|
2452
|
+
tags,
|
|
2453
|
+
});
|
|
1525
2454
|
return {
|
|
1526
2455
|
content: [{
|
|
1527
2456
|
type: "text",
|
|
1528
2457
|
text: JSON.stringify({
|
|
1529
2458
|
success: true,
|
|
1530
|
-
message: `
|
|
2459
|
+
message: `Movie '${movie.title}' added to Radarr`,
|
|
2460
|
+
movieId: movie.id,
|
|
2461
|
+
movie: {
|
|
2462
|
+
id: movie.id,
|
|
2463
|
+
title: movie.title,
|
|
2464
|
+
path: movie.path,
|
|
2465
|
+
monitored: movie.monitored,
|
|
2466
|
+
},
|
|
1531
2467
|
}, null, 2),
|
|
1532
2468
|
}],
|
|
1533
2469
|
};
|
|
1534
2470
|
}
|
|
1535
|
-
case "
|
|
1536
|
-
if (!clients.
|
|
1537
|
-
throw new Error("
|
|
1538
|
-
const {
|
|
1539
|
-
const
|
|
2471
|
+
case "radarr_update_movie": {
|
|
2472
|
+
if (!clients.radarr)
|
|
2473
|
+
throw new Error("Radarr not configured");
|
|
2474
|
+
const { movieId, ...updates } = args;
|
|
2475
|
+
const movie = await clients.radarr.updateMovie(movieId, updates);
|
|
1540
2476
|
return {
|
|
1541
2477
|
content: [{
|
|
1542
2478
|
type: "text",
|
|
1543
2479
|
text: JSON.stringify({
|
|
1544
2480
|
success: true,
|
|
1545
|
-
message: `
|
|
1546
|
-
|
|
1547
|
-
|
|
2481
|
+
message: `Movie '${movie.title}' updated`,
|
|
2482
|
+
movieId: movie.id,
|
|
2483
|
+
updates: Object.keys(updates),
|
|
1548
2484
|
}, null, 2),
|
|
1549
2485
|
}],
|
|
1550
2486
|
};
|
|
1551
2487
|
}
|
|
1552
|
-
case "
|
|
1553
|
-
if (!clients.
|
|
1554
|
-
throw new Error("
|
|
1555
|
-
const {
|
|
1556
|
-
await clients.
|
|
2488
|
+
case "radarr_delete_movie": {
|
|
2489
|
+
if (!clients.radarr)
|
|
2490
|
+
throw new Error("Radarr not configured");
|
|
2491
|
+
const { movieId, deleteFiles = false, addImportExclusion = false } = args;
|
|
2492
|
+
await clients.radarr.deleteMovie(movieId, deleteFiles, addImportExclusion);
|
|
1557
2493
|
return {
|
|
1558
2494
|
content: [{
|
|
1559
2495
|
type: "text",
|
|
1560
2496
|
text: JSON.stringify({
|
|
1561
2497
|
success: true,
|
|
1562
|
-
message: `
|
|
2498
|
+
message: `Movie deleted (files: ${deleteFiles}, exclude: ${addImportExclusion})`,
|
|
1563
2499
|
}, null, 2),
|
|
1564
2500
|
}],
|
|
1565
2501
|
};
|
|
1566
2502
|
}
|
|
1567
|
-
case "
|
|
1568
|
-
if (!clients.
|
|
1569
|
-
throw new Error("
|
|
1570
|
-
const {
|
|
1571
|
-
|
|
2503
|
+
case "radarr_get_history": {
|
|
2504
|
+
if (!clients.radarr)
|
|
2505
|
+
throw new Error("Radarr not configured");
|
|
2506
|
+
const { page = 1, pageSize = 20, movieId } = args;
|
|
2507
|
+
if (movieId) {
|
|
2508
|
+
const history = await clients.radarr.getMovieHistory(movieId);
|
|
2509
|
+
return {
|
|
2510
|
+
content: [{
|
|
2511
|
+
type: "text",
|
|
2512
|
+
text: JSON.stringify({
|
|
2513
|
+
movieId,
|
|
2514
|
+
count: history.length,
|
|
2515
|
+
records: history.map((h) => ({
|
|
2516
|
+
id: h.id,
|
|
2517
|
+
date: h.date,
|
|
2518
|
+
eventType: h.eventType,
|
|
2519
|
+
sourceTitle: h.sourceTitle,
|
|
2520
|
+
quality: h.quality?.quality?.name,
|
|
2521
|
+
downloadId: h.downloadId,
|
|
2522
|
+
})),
|
|
2523
|
+
}, null, 2),
|
|
2524
|
+
}],
|
|
2525
|
+
};
|
|
2526
|
+
}
|
|
2527
|
+
const history = await clients.radarr.getHistory(page, pageSize);
|
|
1572
2528
|
return {
|
|
1573
2529
|
content: [{
|
|
1574
2530
|
type: "text",
|
|
1575
2531
|
text: JSON.stringify({
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
2532
|
+
page,
|
|
2533
|
+
pageSize,
|
|
2534
|
+
totalRecords: history.totalRecords,
|
|
2535
|
+
records: history.records.map((h) => ({
|
|
2536
|
+
id: h.id,
|
|
2537
|
+
movieId: h.movieId,
|
|
2538
|
+
date: h.date,
|
|
2539
|
+
eventType: h.eventType,
|
|
2540
|
+
sourceTitle: h.sourceTitle,
|
|
2541
|
+
quality: h.quality?.quality?.name,
|
|
2542
|
+
})),
|
|
1579
2543
|
}, null, 2),
|
|
1580
2544
|
}],
|
|
1581
2545
|
};
|
|
1582
2546
|
}
|
|
1583
|
-
case "
|
|
1584
|
-
if (!clients.
|
|
1585
|
-
throw new Error("
|
|
1586
|
-
const {
|
|
1587
|
-
const result = await clients.
|
|
2547
|
+
case "radarr_refresh_movie": {
|
|
2548
|
+
if (!clients.radarr)
|
|
2549
|
+
throw new Error("Radarr not configured");
|
|
2550
|
+
const { movieId } = args;
|
|
2551
|
+
const result = await clients.radarr.refreshMovie(movieId);
|
|
1588
2552
|
return {
|
|
1589
2553
|
content: [{
|
|
1590
2554
|
type: "text",
|
|
1591
2555
|
text: JSON.stringify({
|
|
1592
2556
|
success: true,
|
|
1593
|
-
message: `
|
|
2557
|
+
message: `Movie ${movieId} metadata refresh triggered`,
|
|
1594
2558
|
commandId: result.id,
|
|
1595
2559
|
}, null, 2),
|
|
1596
2560
|
}],
|
|
1597
2561
|
};
|
|
1598
2562
|
}
|
|
1599
|
-
case "
|
|
1600
|
-
if (!clients.
|
|
1601
|
-
throw new Error("
|
|
1602
|
-
const {
|
|
1603
|
-
const result = await clients.
|
|
2563
|
+
case "radarr_rescan_movie": {
|
|
2564
|
+
if (!clients.radarr)
|
|
2565
|
+
throw new Error("Radarr not configured");
|
|
2566
|
+
const { movieId } = args;
|
|
2567
|
+
const result = await clients.radarr.rescanMovie(movieId);
|
|
1604
2568
|
return {
|
|
1605
2569
|
content: [{
|
|
1606
2570
|
type: "text",
|
|
1607
2571
|
text: JSON.stringify({
|
|
1608
2572
|
success: true,
|
|
1609
|
-
message: `
|
|
2573
|
+
message: `Movie ${movieId} disk rescan triggered`,
|
|
1610
2574
|
commandId: result.id,
|
|
1611
2575
|
}, null, 2),
|
|
1612
2576
|
}],
|
|
1613
2577
|
};
|
|
1614
2578
|
}
|
|
1615
|
-
case "
|
|
1616
|
-
if (!clients.
|
|
1617
|
-
throw new Error("
|
|
1618
|
-
const {
|
|
1619
|
-
const result = await clients.
|
|
2579
|
+
case "radarr_rename_movie": {
|
|
2580
|
+
if (!clients.radarr)
|
|
2581
|
+
throw new Error("Radarr not configured");
|
|
2582
|
+
const { movieId } = args;
|
|
2583
|
+
const result = await clients.radarr.renameMovie(movieId);
|
|
1620
2584
|
return {
|
|
1621
2585
|
content: [{
|
|
1622
2586
|
type: "text",
|
|
1623
2587
|
text: JSON.stringify({
|
|
1624
2588
|
success: true,
|
|
1625
|
-
message: `
|
|
2589
|
+
message: `Movie ${movieId} files will be renamed`,
|
|
1626
2590
|
commandId: result.id,
|
|
1627
2591
|
}, null, 2),
|
|
1628
2592
|
}],
|
|
1629
2593
|
};
|
|
1630
2594
|
}
|
|
1631
|
-
case "
|
|
1632
|
-
if (!clients.
|
|
1633
|
-
throw new Error("
|
|
1634
|
-
const
|
|
1635
|
-
const releases = await clients.sonarr.getReleases(seriesId, page, pageSize);
|
|
2595
|
+
case "radarr_get_collections": {
|
|
2596
|
+
if (!clients.radarr)
|
|
2597
|
+
throw new Error("Radarr not configured");
|
|
2598
|
+
const collections = await clients.radarr.getCollections();
|
|
1636
2599
|
return {
|
|
1637
2600
|
content: [{
|
|
1638
2601
|
type: "text",
|
|
1639
2602
|
text: JSON.stringify({
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
age: r.age,
|
|
1650
|
-
ageHours: r.ageHours,
|
|
1651
|
-
rejected: r.rejected,
|
|
1652
|
-
rejectionReason: r.rejectionReason,
|
|
1653
|
-
publishedDate: r.publishedDate,
|
|
2603
|
+
count: collections.length,
|
|
2604
|
+
collections: collections.map((c) => ({
|
|
2605
|
+
id: c.id,
|
|
2606
|
+
title: c.title,
|
|
2607
|
+
tmdbId: c.tmdbId,
|
|
2608
|
+
monitored: c.monitored,
|
|
2609
|
+
movieCount: c.movies?.length || 0,
|
|
2610
|
+
qualityProfileId: c.qualityProfileId,
|
|
2611
|
+
rootFolderPath: c.rootFolderPath,
|
|
1654
2612
|
})),
|
|
1655
2613
|
}, null, 2),
|
|
1656
2614
|
}],
|
|
1657
2615
|
};
|
|
1658
2616
|
}
|
|
1659
|
-
case "
|
|
1660
|
-
if (!clients.
|
|
1661
|
-
throw new Error("
|
|
1662
|
-
const {
|
|
1663
|
-
await clients.
|
|
2617
|
+
case "radarr_update_collection": {
|
|
2618
|
+
if (!clients.radarr)
|
|
2619
|
+
throw new Error("Radarr not configured");
|
|
2620
|
+
const { collectionId, ...updates } = args;
|
|
2621
|
+
const collection = await clients.radarr.updateCollection(collectionId, updates);
|
|
1664
2622
|
return {
|
|
1665
2623
|
content: [{
|
|
1666
2624
|
type: "text",
|
|
1667
2625
|
text: JSON.stringify({
|
|
1668
2626
|
success: true,
|
|
1669
|
-
message: `
|
|
2627
|
+
message: `Collection '${collection.title}' updated`,
|
|
2628
|
+
collectionId: collection.id,
|
|
2629
|
+
updates: Object.keys(updates),
|
|
1670
2630
|
}, null, 2),
|
|
1671
2631
|
}],
|
|
1672
2632
|
};
|
|
1673
2633
|
}
|
|
1674
|
-
case "
|
|
1675
|
-
if (!clients.
|
|
1676
|
-
throw new Error("
|
|
1677
|
-
const
|
|
2634
|
+
case "radarr_get_movie_files": {
|
|
2635
|
+
if (!clients.radarr)
|
|
2636
|
+
throw new Error("Radarr not configured");
|
|
2637
|
+
const { movieId } = args;
|
|
2638
|
+
const files = await clients.radarr.getMovieFiles(movieId);
|
|
1678
2639
|
return {
|
|
1679
2640
|
content: [{
|
|
1680
2641
|
type: "text",
|
|
1681
2642
|
text: JSON.stringify({
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
2643
|
+
movieId,
|
|
2644
|
+
count: files.length,
|
|
2645
|
+
files: files.map((f) => ({
|
|
2646
|
+
id: f.id,
|
|
2647
|
+
relativePath: f.relativePath,
|
|
2648
|
+
size: formatBytes(f.size),
|
|
2649
|
+
quality: f.quality?.quality?.name,
|
|
2650
|
+
dateAdded: f.dateAdded,
|
|
2651
|
+
mediaInfo: f.mediaInfo ? {
|
|
2652
|
+
resolution: f.mediaInfo.resolution,
|
|
2653
|
+
videoCodec: f.mediaInfo.videoCodec,
|
|
2654
|
+
audioCodec: f.mediaInfo.audioCodec,
|
|
2655
|
+
audioChannels: f.mediaInfo.audioChannels,
|
|
2656
|
+
runTime: f.mediaInfo.runTime,
|
|
2657
|
+
} : null,
|
|
2658
|
+
})),
|
|
1686
2659
|
}, null, 2),
|
|
1687
2660
|
}],
|
|
1688
2661
|
};
|
|
1689
2662
|
}
|
|
1690
|
-
case "
|
|
1691
|
-
if (!clients.
|
|
1692
|
-
throw new Error("
|
|
1693
|
-
const {
|
|
1694
|
-
|
|
2663
|
+
case "radarr_delete_movie_file": {
|
|
2664
|
+
if (!clients.radarr)
|
|
2665
|
+
throw new Error("Radarr not configured");
|
|
2666
|
+
const { movieFileId } = args;
|
|
2667
|
+
await clients.radarr.deleteMovieFile(movieFileId);
|
|
1695
2668
|
return {
|
|
1696
2669
|
content: [{
|
|
1697
2670
|
type: "text",
|
|
1698
2671
|
text: JSON.stringify({
|
|
1699
2672
|
success: true,
|
|
1700
|
-
message: `
|
|
1701
|
-
profileId: profile.id,
|
|
1702
|
-
profile,
|
|
2673
|
+
message: `Movie file ${movieFileId} deleted`,
|
|
1703
2674
|
}, null, 2),
|
|
1704
2675
|
}],
|
|
1705
2676
|
};
|
|
1706
2677
|
}
|
|
1707
|
-
case "
|
|
1708
|
-
if (!clients.
|
|
1709
|
-
throw new Error("
|
|
1710
|
-
const {
|
|
1711
|
-
await clients.
|
|
2678
|
+
case "radarr_get_blocklist": {
|
|
2679
|
+
if (!clients.radarr)
|
|
2680
|
+
throw new Error("Radarr not configured");
|
|
2681
|
+
const { page = 1, pageSize = 20 } = args;
|
|
2682
|
+
const blocklist = await clients.radarr.getBlocklist(page, pageSize);
|
|
1712
2683
|
return {
|
|
1713
2684
|
content: [{
|
|
1714
2685
|
type: "text",
|
|
1715
2686
|
text: JSON.stringify({
|
|
1716
|
-
|
|
1717
|
-
|
|
2687
|
+
page,
|
|
2688
|
+
pageSize,
|
|
2689
|
+
totalRecords: blocklist.totalRecords,
|
|
2690
|
+
records: blocklist.records.map((b) => ({
|
|
2691
|
+
id: b.id,
|
|
2692
|
+
movieId: b.movieId,
|
|
2693
|
+
sourceTitle: b.sourceTitle,
|
|
2694
|
+
date: b.date,
|
|
2695
|
+
protocol: b.protocol,
|
|
2696
|
+
indexer: b.indexer,
|
|
2697
|
+
message: b.message,
|
|
2698
|
+
})),
|
|
1718
2699
|
}, null, 2),
|
|
1719
2700
|
}],
|
|
1720
2701
|
};
|
|
1721
2702
|
}
|
|
1722
|
-
case "
|
|
1723
|
-
if (!clients.
|
|
1724
|
-
throw new Error("
|
|
1725
|
-
const {
|
|
1726
|
-
|
|
2703
|
+
case "radarr_delete_blocklist_item": {
|
|
2704
|
+
if (!clients.radarr)
|
|
2705
|
+
throw new Error("Radarr not configured");
|
|
2706
|
+
const { blocklistId } = args;
|
|
2707
|
+
await clients.radarr.deleteBlocklistItem(blocklistId);
|
|
1727
2708
|
return {
|
|
1728
2709
|
content: [{
|
|
1729
2710
|
type: "text",
|
|
1730
2711
|
text: JSON.stringify({
|
|
1731
2712
|
success: true,
|
|
1732
|
-
message: `
|
|
1733
|
-
tagId: tag.id,
|
|
1734
|
-
tag,
|
|
2713
|
+
message: `Blocklist item ${blocklistId} deleted`,
|
|
1735
2714
|
}, null, 2),
|
|
1736
2715
|
}],
|
|
1737
2716
|
};
|
|
1738
2717
|
}
|
|
1739
|
-
case "
|
|
1740
|
-
if (!clients.
|
|
1741
|
-
throw new Error("
|
|
1742
|
-
const {
|
|
1743
|
-
const
|
|
2718
|
+
case "radarr_get_extra_files": {
|
|
2719
|
+
if (!clients.radarr)
|
|
2720
|
+
throw new Error("Radarr not configured");
|
|
2721
|
+
const { movieId } = args;
|
|
2722
|
+
const files = await clients.radarr.getExtraFiles(movieId);
|
|
1744
2723
|
return {
|
|
1745
2724
|
content: [{
|
|
1746
2725
|
type: "text",
|
|
1747
2726
|
text: JSON.stringify({
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
2727
|
+
movieId,
|
|
2728
|
+
count: files.length,
|
|
2729
|
+
files: files.map((f) => ({
|
|
2730
|
+
id: f.id,
|
|
2731
|
+
relativePath: f.relativePath,
|
|
2732
|
+
extension: f.extension,
|
|
2733
|
+
type: f.type,
|
|
2734
|
+
})),
|
|
1752
2735
|
}, null, 2),
|
|
1753
2736
|
}],
|
|
1754
2737
|
};
|
|
1755
2738
|
}
|
|
1756
|
-
case "
|
|
1757
|
-
if (!clients.
|
|
1758
|
-
throw new Error("
|
|
1759
|
-
const {
|
|
1760
|
-
await clients.
|
|
2739
|
+
case "radarr_get_credits": {
|
|
2740
|
+
if (!clients.radarr)
|
|
2741
|
+
throw new Error("Radarr not configured");
|
|
2742
|
+
const { movieId } = args;
|
|
2743
|
+
const credits = await clients.radarr.getCredits(movieId);
|
|
1761
2744
|
return {
|
|
1762
2745
|
content: [{
|
|
1763
2746
|
type: "text",
|
|
1764
2747
|
text: JSON.stringify({
|
|
1765
|
-
|
|
1766
|
-
|
|
2748
|
+
movieId,
|
|
2749
|
+
count: credits.length,
|
|
2750
|
+
cast: credits.filter((c) => c.type === 'cast').slice(0, 20).map((c) => ({
|
|
2751
|
+
name: c.personName,
|
|
2752
|
+
character: c.character,
|
|
2753
|
+
order: c.order,
|
|
2754
|
+
})),
|
|
2755
|
+
crew: credits.filter((c) => c.type === 'crew').slice(0, 10).map((c) => ({
|
|
2756
|
+
name: c.personName,
|
|
2757
|
+
job: c.job,
|
|
2758
|
+
department: c.department,
|
|
2759
|
+
})),
|
|
1767
2760
|
}, null, 2),
|
|
1768
2761
|
}],
|
|
1769
2762
|
};
|
|
1770
2763
|
}
|
|
1771
|
-
|
|
1772
|
-
case "radarr_get_movies": {
|
|
2764
|
+
case "radarr_get_wanted": {
|
|
1773
2765
|
if (!clients.radarr)
|
|
1774
2766
|
throw new Error("Radarr not configured");
|
|
1775
|
-
const
|
|
2767
|
+
const { page = 1, pageSize = 20 } = args;
|
|
2768
|
+
const wanted = await clients.radarr.getWanted(page, pageSize);
|
|
1776
2769
|
return {
|
|
1777
2770
|
content: [{
|
|
1778
2771
|
type: "text",
|
|
1779
2772
|
text: JSON.stringify({
|
|
1780
|
-
|
|
1781
|
-
|
|
2773
|
+
page,
|
|
2774
|
+
pageSize,
|
|
2775
|
+
totalRecords: wanted.totalRecords,
|
|
2776
|
+
movies: wanted.records.map((m) => ({
|
|
1782
2777
|
id: m.id,
|
|
1783
2778
|
title: m.title,
|
|
1784
2779
|
year: m.year,
|
|
1785
2780
|
status: m.status,
|
|
1786
|
-
hasFile: m.hasFile,
|
|
1787
|
-
sizeOnDisk: formatBytes(m.sizeOnDisk),
|
|
1788
2781
|
monitored: m.monitored,
|
|
1789
|
-
|
|
2782
|
+
isAvailable: m.isAvailable,
|
|
2783
|
+
minimumAvailability: m.minimumAvailability,
|
|
1790
2784
|
})),
|
|
1791
2785
|
}, null, 2),
|
|
1792
2786
|
}],
|
|
1793
2787
|
};
|
|
1794
2788
|
}
|
|
1795
|
-
case "
|
|
2789
|
+
case "radarr_search_missing": {
|
|
1796
2790
|
if (!clients.radarr)
|
|
1797
2791
|
throw new Error("Radarr not configured");
|
|
1798
|
-
const
|
|
1799
|
-
const results = await clients.radarr.searchMovies(term);
|
|
2792
|
+
const result = await clients.radarr.searchMissing();
|
|
1800
2793
|
return {
|
|
1801
2794
|
content: [{
|
|
1802
2795
|
type: "text",
|
|
1803
2796
|
text: JSON.stringify({
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
year: r.year,
|
|
1808
|
-
tmdbId: r.tmdbId,
|
|
1809
|
-
imdbId: r.imdbId,
|
|
1810
|
-
overview: r.overview?.substring(0, 200) + (r.overview && r.overview.length > 200 ? '...' : ''),
|
|
1811
|
-
})),
|
|
2797
|
+
success: true,
|
|
2798
|
+
message: 'Search triggered for all missing movies',
|
|
2799
|
+
commandId: result.id,
|
|
1812
2800
|
}, null, 2),
|
|
1813
2801
|
}],
|
|
1814
2802
|
};
|
|
1815
2803
|
}
|
|
1816
|
-
case "
|
|
2804
|
+
case "radarr_create_tag": {
|
|
1817
2805
|
if (!clients.radarr)
|
|
1818
2806
|
throw new Error("Radarr not configured");
|
|
1819
|
-
const
|
|
2807
|
+
const { label } = args;
|
|
2808
|
+
const tag = await clients.radarr.createTag(label);
|
|
1820
2809
|
return {
|
|
1821
2810
|
content: [{
|
|
1822
2811
|
type: "text",
|
|
1823
2812
|
text: JSON.stringify({
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
progress: ((1 - q.sizeleft / q.size) * 100).toFixed(1) + '%',
|
|
1829
|
-
timeLeft: q.timeleft,
|
|
1830
|
-
downloadClient: q.downloadClient,
|
|
1831
|
-
})),
|
|
2813
|
+
success: true,
|
|
2814
|
+
message: `Tag '${label}' created`,
|
|
2815
|
+
tagId: tag.id,
|
|
2816
|
+
tag,
|
|
1832
2817
|
}, null, 2),
|
|
1833
2818
|
}],
|
|
1834
2819
|
};
|
|
1835
2820
|
}
|
|
1836
|
-
case "
|
|
2821
|
+
case "radarr_update_tag": {
|
|
1837
2822
|
if (!clients.radarr)
|
|
1838
2823
|
throw new Error("Radarr not configured");
|
|
1839
|
-
const
|
|
1840
|
-
const
|
|
1841
|
-
const end = new Date(Date.now() + days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
1842
|
-
const calendar = await clients.radarr.getCalendar(start, end);
|
|
2824
|
+
const { tagId, label } = args;
|
|
2825
|
+
const tag = await clients.radarr.updateTag(tagId, label);
|
|
1843
2826
|
return {
|
|
1844
|
-
content: [{
|
|
2827
|
+
content: [{
|
|
2828
|
+
type: "text",
|
|
2829
|
+
text: JSON.stringify({
|
|
2830
|
+
success: true,
|
|
2831
|
+
message: `Tag ${tagId} updated to '${label}'`,
|
|
2832
|
+
tagId: tag.id,
|
|
2833
|
+
tag,
|
|
2834
|
+
}, null, 2),
|
|
2835
|
+
}],
|
|
1845
2836
|
};
|
|
1846
2837
|
}
|
|
1847
|
-
case "
|
|
2838
|
+
case "radarr_delete_tag": {
|
|
1848
2839
|
if (!clients.radarr)
|
|
1849
2840
|
throw new Error("Radarr not configured");
|
|
1850
|
-
const
|
|
1851
|
-
|
|
2841
|
+
const { tagId } = args;
|
|
2842
|
+
await clients.radarr.deleteTag(tagId);
|
|
1852
2843
|
return {
|
|
1853
2844
|
content: [{
|
|
1854
2845
|
type: "text",
|
|
1855
2846
|
text: JSON.stringify({
|
|
1856
2847
|
success: true,
|
|
1857
|
-
message: `
|
|
1858
|
-
commandId: result.id,
|
|
2848
|
+
message: `Tag ${tagId} deleted`,
|
|
1859
2849
|
}, null, 2),
|
|
1860
2850
|
}],
|
|
1861
2851
|
};
|