Skip to content

Instantly share code, notes, and snippets.

@Fronix
Last active July 24, 2021 15:57

Revisions

  1. Oscar Martin revised this gist Jul 24, 2021. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions RadarrTautulliPlexDelete.js
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,5 @@
    {
    /** OUTDATED **/
    //based on https://gist.github.com/ojame/93560d99149124ea2f89b9d78cbcadd1
    // RadarrAPI: Go to Radarr and click 'settings' => 'general'.
    // TautulliAPI: Go to Tautulli and click 'Settings' => 'Web Interface'
  2. Oscar Martin revised this gist Apr 9, 2020. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions RadarrTautulliPlexDelete.js
    Original file line number Diff line number Diff line change
    @@ -73,7 +73,7 @@ function getMonthsBetween(date1,date2) {
    return `[${(((index + 1) / _movies.length) * 100).toFixed(2)}%]`
    }

    const FAKEdeleteMovie = (id) =>
    const deleteMovie = (id) =>
    fetch(`${radarrUrl}${id}?deleteFiles=${deleteFiles}&addExclusion=false`, {
    method: 'DELETE',
    headers: {
    @@ -94,7 +94,7 @@ function getMonthsBetween(date1,date2) {
    }
    });

    const deleteMovie = (id) => {
    const FAKEdeleteMovie = (id) => {
    index++;
    if(blacklistedRadarrIds.includes(ids[index])){
    console.log(`${_movies.find(m => m.id === ids[index]).title} is blacklisted. Skipping`);
  3. Oscar Martin revised this gist Apr 8, 2020. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions RadarrTautulliPlexDelete.js
    Original file line number Diff line number Diff line change
    @@ -30,12 +30,12 @@

    // How many months old a movie has to be to be deleted (example: 5 = all movies older than 5 months get deleted)
    // Format: numeric
    const monthsSinceAdded = 5;
    const monthsSinceAdded = 5; // set to null to disable

    // If you want to delete movies based on when it was last played put a date in this setting
    // Example: 2019-05-05 = All movies that were last played before this date will be deleted (movies that were never watched don't get deleted)
    // Format: YYYY-MM-DD
    const lastPlayedOlderThan = null;
    const lastPlayedOlderThan = null; // set to null to disable
    // -- END of these settings decide when movies get deleted -- //

    //end of configs
  4. Oscar Martin revised this gist Apr 8, 2020. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions RadarrTautulliPlexDelete.js
    Original file line number Diff line number Diff line change
    @@ -6,6 +6,10 @@
    // Past the following in. Hit enter and away you go.
    // Alternatively you can use Sources->Snippets in Chrome

    //Update 2020-04-08:
    // Added possibility to delete movies based on last_played date
    // If lastPlayedOlderThan < lastPlayedDate the movie will be deleted (movies with no last_played date don't get deleted)

    //Blacklist ids that you still want to keep (these wont get deleted)
    const blacklistedRadarrIds = [];

  5. Oscar Martin revised this gist Apr 8, 2020. 1 changed file with 84 additions and 29 deletions.
    113 changes: 84 additions & 29 deletions RadarrTautulliPlexDelete.js
    Original file line number Diff line number Diff line change
    @@ -15,14 +15,24 @@
    const tautulliUrl = '';
    const tautulliApiKey = '';

    //The sectionId for your library (Find it in Tautulli>Libraries click on your library and check the url for ?section_id=> 1 <)
    const tautulliSectionId = '1';
    //The sectionId for your library (Find it in Tautulli>Libraries click on your library and check the url for ?section_id=X)
    const tautulliSectionId = '';

    //Set to TRUE if you want Radarr to delete these files (they will be unavaiable in Plex after)
    //Set to TRUE if you want Radarr to delete these files (they will be unavaiable in Plex after *BE CAREFUL*)
    const deleteFiles = false;

    //How many months old a movie has to be to be deleted
    // -- These settings decide when movies get deleted -- //
    // Only one of these settings can be set at a time

    // How many months old a movie has to be to be deleted (example: 5 = all movies older than 5 months get deleted)
    // Format: numeric
    const monthsSinceAdded = 5;

    // If you want to delete movies based on when it was last played put a date in this setting
    // Example: 2019-05-05 = All movies that were last played before this date will be deleted (movies that were never watched don't get deleted)
    // Format: YYYY-MM-DD
    const lastPlayedOlderThan = null;
    // -- END of these settings decide when movies get deleted -- //

    //end of configs
    let ids = [];
    @@ -59,7 +69,7 @@ function getMonthsBetween(date1,date2) {
    return `[${(((index + 1) / _movies.length) * 100).toFixed(2)}%]`
    }

    const deleteMovie = (id) =>
    const FAKEdeleteMovie = (id) =>
    fetch(`${radarrUrl}${id}?deleteFiles=${deleteFiles}&addExclusion=false`, {
    method: 'DELETE',
    headers: {
    @@ -80,7 +90,7 @@ function getMonthsBetween(date1,date2) {
    }
    });

    const FAKEdeleteMovie = (id) => {
    const deleteMovie = (id) => {
    index++;
    if(blacklistedRadarrIds.includes(ids[index])){
    console.log(`${_movies.find(m => m.id === ids[index]).title} is blacklisted. Skipping`);
    @@ -95,6 +105,12 @@ function getMonthsBetween(date1,date2) {
    }
    }

    const getLastPlayedAt = (lpd, mlpd) => {
    const lastPlayed = new Date(lpd);
    const minLastPlayed = new Date(mlpd);
    return lastPlayed < minLastPlayed;
    }

    const getUnwatchedLibraryMedaInfo = () =>
    fetch(`${tautulliUrl}get_library_media_info?apikey=${tautulliApiKey}&section_id=${tautulliSectionId}&length=500`, {
    method: 'GET',
    @@ -110,38 +126,77 @@ function getMonthsBetween(date1,date2) {

    const getAllMovieInfo = () => Promise.all([getRadarrMovies(), getUnwatchedLibraryMedaInfo()]);

    const getNiceDate = (date) => new Date(date.getTime() - (date.getTimezoneOffset() * 60000 )).toISOString().split("T")[0];
    const longest = (key, array) => Math.max(...array.map(it => it[key].length));
    const addNumSpaces = (num) => ' '.repeat(num) + '|';

    if(!radarrUrl || !tautulliUrl || !radarrApiKey || !tautulliApiKey) {
    alert('You need to setup your urls and api keys')
    } else {
    getAllMovieInfo().then(([radarrMovies, tatulliMovies]) => {
    console.log('Movie info fetched!');
    const unwatchedMovies = tatulliMovies.filter(x => !x.play_count)
    const neverDownloaded = radarrMovies.filter(m => !m.downloaded && m.status === "released" && getMonthsBetween(new Date(m.added), new Date()) >= monthsSinceAdded);
    const neverWatched = radarrMovies.filter(m => unwatchedMovies.find(({ title, added_at }) => m.title === title && getMonthsBetween(new Date(added_at * 1000), new Date()) >= monthsSinceAdded));

    _movies = neverDownloaded.concat(neverWatched);
    ids = _movies.map(x => x.id);
    console.log('Sure you want to delete these movies?:');
    _movies.map(x => console.log(x.title, 'added', getMonthsBetween(new Date(x.added), new Date()), 'months ago', `(id: ${x.id})`))
    const confirm = window.confirm('Sure you want to delete these movies? (Check console)');


    if(confirm) {
    console.log('OK deleting..');
    if(blacklistedRadarrIds.includes(ids[index])){
    console.log(`${_movies.find(m => m.id === ids[index]).title} is blacklisted. Skipping`);
    deleteMovie(ids[index + 1]);


    if(!monthsSinceAdded && lastPlayedOlderThan) {
    const moviesToDelete = radarrMovies.filter(m => tatulliMovies.find(({ title, last_played }) => m.title === title && last_played !== null && getLastPlayedAt(last_played * 1000, lastPlayedOlderThan)))
    .map(m => tatulliMovies.find(({ title }) => m.title === title) && ({...m, last_played: tatulliMovies.find(({ title }) => m.title === title).last_played}));


    _movies = moviesToDelete;
    ids = _movies.map(x => x.id);
    console.log('Sure you want to delete these movies?:');
    _movies.map(x => console.log(x.title, x.title.length < longest('title', _movies) ? addNumSpaces(longest('title', _movies) - x.title.length) : addNumSpaces(0), 'Last played:', getNiceDate(new Date(x.last_played * 1000)), '|', `(id: ${x.id})`))
    const confirm = window.confirm('Sure you want to delete these movies? (Check console)');


    if(confirm) {
    console.log('OK deleting..');
    if(blacklistedRadarrIds.includes(ids[index])){
    console.log(`${_movies.find(m => m.id === ids[index]).title} is blacklisted. Skipping`);
    deleteMovie(ids[index + 1]);
    } else {
    if (ids.length) {
    console.log(`${percentage()} Deleting ${_movies.find(m => m.id === ids[index]).title}`);
    deleteMovie(ids[index]);
    } else {
    console.log('There doesn`t seem to be any movies to delete');
    }
    }
    } else {
    if (ids.length) {
    console.log(`${percentage()} Deleting ${_movies.find(m => m.id === ids[index]).title}`);
    deleteMovie(ids[index]);
    console.log('Aborted')
    }

    } else if (monthsSinceAdded && !lastPlayedOlderThan) {
    const unwatchedMovies = tatulliMovies.filter(x => !x.play_count)
    const neverDownloaded = radarrMovies.filter(m => !m.downloaded && m.status === "released" && getMonthsBetween(new Date(m.added), new Date()) >= monthsSinceAdded);
    const neverWatched = radarrMovies.filter(m => unwatchedMovies.find(({ title, added_at }) => m.title === title && getMonthsBetween(new Date(added_at * 1000), new Date()) >= monthsSinceAdded));
    _movies = neverDownloaded.concat(neverWatched);
    ids = _movies.map(x => x.id);
    console.log('Sure you want to delete these movies?:');
    _movies.map(x => console.log(x.title, x.title.length < longest('title', _movies) ? addNumSpaces(longest('title', _movies) - x.title.length) : addNumSpaces(0), 'added', getMonthsBetween(new Date(x.added), new Date()), 'months ago', `(id: ${x.id})`))
    const confirm = window.confirm('Sure you want to delete these movies? (Check console)');


    if(confirm) {
    console.log('OK deleting..');
    if(blacklistedRadarrIds.includes(ids[index])){
    console.log(`${_movies.find(m => m.id === ids[index]).title} is blacklisted. Skipping`);
    deleteMovie(ids[index + 1]);
    } else {
    console.log('There doesn`t seem to be any movies to delete');
    if (ids.length) {
    console.log(`${percentage()} Deleting ${_movies.find(m => m.id === ids[index]).title}`);
    deleteMovie(ids[index]);
    } else {
    console.log('There doesn`t seem to be any movies to delete');
    }
    }
    } else {
    console.log('Aborted')
    }
    } else {
    console.log('Aborted')
    }
    } else {
    console.log('You have not set either monthsSinceAdded or lastPlayedOlderThan, choose one option')
    return;
    }
    });
    }
    }
  6. Oscar Martin revised this gist Apr 7, 2020. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions RadarrTautulliPlexDelete.js
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,10 @@
    {
    //based on https://gist.github.com/ojame/93560d99149124ea2f89b9d78cbcadd1
    // RadarrAPI: Go to Radarr and click 'settings' => 'general'.
    // TautulliAPI: Go to Tautulli and click 'Settings' => 'Web Interface'
    // Open the JavaScript Console in Google Chrome (View => Developer => Javascript Console)
    // Past the following in. Hit enter and away you go.
    // Alternatively you can use Sources->Snippets in Chrome

    //Blacklist ids that you still want to keep (these wont get deleted)
    const blacklistedRadarrIds = [];
  7. Oscar Martin revised this gist Apr 7, 2020. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions RadarrTautulliPlexDelete.js
    Original file line number Diff line number Diff line change
    @@ -54,7 +54,7 @@ function getMonthsBetween(date1,date2) {
    return `[${(((index + 1) / _movies.length) * 100).toFixed(2)}%]`
    }

    const DISABLEDdeleteMovie = (id) =>
    const deleteMovie = (id) =>
    fetch(`${radarrUrl}${id}?deleteFiles=${deleteFiles}&addExclusion=false`, {
    method: 'DELETE',
    headers: {
    @@ -75,7 +75,7 @@ function getMonthsBetween(date1,date2) {
    }
    });

    const deleteMovie = (id) => {
    const FAKEdeleteMovie = (id) => {
    index++;
    if(blacklistedRadarrIds.includes(ids[index])){
    console.log(`${_movies.find(m => m.id === ids[index]).title} is blacklisted. Skipping`);
  8. Oscar Martin revised this gist Apr 7, 2020. 1 changed file with 7 additions and 4 deletions.
    11 changes: 7 additions & 4 deletions RadarrTautulliPlexDelete.js
    Original file line number Diff line number Diff line change
    @@ -10,6 +10,9 @@
    const tautulliUrl = '';
    const tautulliApiKey = '';

    //The sectionId for your library (Find it in Tautulli>Libraries click on your library and check the url for ?section_id=> 1 <)
    const tautulliSectionId = '1';

    //Set to TRUE if you want Radarr to delete these files (they will be unavaiable in Plex after)
    const deleteFiles = false;

    @@ -20,7 +23,7 @@
    let ids = [];
    let _movies = [];
    let index = 0;

    function getMonthsBetween(date1,date2) {
    var roundUpFractionalMonths = false;
    var startDate=date1;
    @@ -51,7 +54,7 @@ function getMonthsBetween(date1,date2) {
    return `[${(((index + 1) / _movies.length) * 100).toFixed(2)}%]`
    }

    const deleteMovie = (id) =>
    const DISABLEDdeleteMovie = (id) =>
    fetch(`${radarrUrl}${id}?deleteFiles=${deleteFiles}&addExclusion=false`, {
    method: 'DELETE',
    headers: {
    @@ -72,7 +75,7 @@ function getMonthsBetween(date1,date2) {
    }
    });

    const FAKEdeleteMovie = (id) => {
    const deleteMovie = (id) => {
    index++;
    if(blacklistedRadarrIds.includes(ids[index])){
    console.log(`${_movies.find(m => m.id === ids[index]).title} is blacklisted. Skipping`);
    @@ -88,7 +91,7 @@ function getMonthsBetween(date1,date2) {
    }

    const getUnwatchedLibraryMedaInfo = () =>
    fetch(`${tautulliUrl}get_library_media_info?apikey=${tautulliApiKey}&section_id=1&length=500`, {
    fetch(`${tautulliUrl}get_library_media_info?apikey=${tautulliApiKey}&section_id=${tautulliSectionId}&length=500`, {
    method: 'GET',
    }).then(res => res.json()).then(movies => movies.data);

  9. Oscar Martin revised this gist Apr 7, 2020. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions RadarrTautulliPlexDelete.js
    Original file line number Diff line number Diff line change
    @@ -51,7 +51,7 @@ function getMonthsBetween(date1,date2) {
    return `[${(((index + 1) / _movies.length) * 100).toFixed(2)}%]`
    }

    const DISABLEDdeleteMovie = (id) =>
    const deleteMovie = (id) =>
    fetch(`${radarrUrl}${id}?deleteFiles=${deleteFiles}&addExclusion=false`, {
    method: 'DELETE',
    headers: {
    @@ -72,7 +72,7 @@ function getMonthsBetween(date1,date2) {
    }
    });

    const deleteMovie = (id) => {
    const FAKEdeleteMovie = (id) => {
    index++;
    if(blacklistedRadarrIds.includes(ids[index])){
    console.log(`${_movies.find(m => m.id === ids[index]).title} is blacklisted. Skipping`);
  10. Oscar Martin created this gist Apr 7, 2020.
    139 changes: 139 additions & 0 deletions RadarrTautulliPlexDelete.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,139 @@
    {
    //based on https://gist.github.com/ojame/93560d99149124ea2f89b9d78cbcadd1

    //Blacklist ids that you still want to keep (these wont get deleted)
    const blacklistedRadarrIds = [];

    //Configure your API information for Radarr and Tautulli
    const radarrUrl = '';
    const radarrApiKey = '';
    const tautulliUrl = '';
    const tautulliApiKey = '';

    //Set to TRUE if you want Radarr to delete these files (they will be unavaiable in Plex after)
    const deleteFiles = false;

    //How many months old a movie has to be to be deleted
    const monthsSinceAdded = 5;

    //end of configs
    let ids = [];
    let _movies = [];
    let index = 0;

    function getMonthsBetween(date1,date2) {
    var roundUpFractionalMonths = false;
    var startDate=date1;
    var endDate=date2;
    var inverse=false;
    if(date1>date2)
    {
    startDate=date2;
    endDate=date1;
    inverse=true;
    }
    var yearsDifference=endDate.getFullYear()-startDate.getFullYear();
    var monthsDifference=endDate.getMonth()-startDate.getMonth();
    var daysDifference=endDate.getDate()-startDate.getDate();
    var monthCorrection=0;
    if(roundUpFractionalMonths && daysDifference>0)
    {
    monthCorrection=1;
    }
    else if(roundUpFractionalMonths!==true && daysDifference<0)
    {
    monthCorrection=-1;
    }
    return (inverse?-1:1)*(yearsDifference*12+monthsDifference+monthCorrection);
    };

    function percentage() {
    return `[${(((index + 1) / _movies.length) * 100).toFixed(2)}%]`
    }

    const DISABLEDdeleteMovie = (id) =>
    fetch(`${radarrUrl}${id}?deleteFiles=${deleteFiles}&addExclusion=false`, {
    method: 'DELETE',
    headers: {
    'X-Api-Key': radarrApiKey,
    },
    }).then(() => {
    index++;
    if(blacklistedRadarrIds.includes(ids[index])){
    console.log(`${_movies.find(m => m.id === ids[index]).title} is blacklisted. Skipping`);
    deleteMovie(ids[index + 1]);
    } else {
    if (ids[index]) {
    console.log(`${percentage()} Deleting ${_movies.find(m => m.id === ids[index]).title}`);
    deleteMovie(ids[index]);
    } else {
    console.log('Finished deleting movies')
    }
    }
    });

    const deleteMovie = (id) => {
    index++;
    if(blacklistedRadarrIds.includes(ids[index])){
    console.log(`${_movies.find(m => m.id === ids[index]).title} is blacklisted. Skipping`);
    deleteMovie(ids[index + 1]);
    } else {
    if (ids[index]) {
    console.log(`${percentage()} Deleting ${_movies.find(m => m.id === ids[index]).title}`);
    deleteMovie(ids[index]);
    } else {
    console.log('Finished deleting movies')
    }
    }
    }

    const getUnwatchedLibraryMedaInfo = () =>
    fetch(`${tautulliUrl}get_library_media_info?apikey=${tautulliApiKey}&section_id=1&length=500`, {
    method: 'GET',
    }).then(res => res.json()).then(movies => movies.data);

    const getRadarrMovies = () =>
    fetch(`${radarrUrl}`, {
    method: 'GET',
    headers: {
    'X-Api-Key': radarrApiKey,
    }
    }).then(res => res.json()).then(movies => movies);

    const getAllMovieInfo = () => Promise.all([getRadarrMovies(), getUnwatchedLibraryMedaInfo()]);

    if(!radarrUrl || !tautulliUrl || !radarrApiKey || !tautulliApiKey) {
    alert('You need to setup your urls and api keys')
    } else {
    getAllMovieInfo().then(([radarrMovies, tatulliMovies]) => {
    console.log('Movie info fetched!');
    const unwatchedMovies = tatulliMovies.filter(x => !x.play_count)
    const neverDownloaded = radarrMovies.filter(m => !m.downloaded && m.status === "released" && getMonthsBetween(new Date(m.added), new Date()) >= monthsSinceAdded);
    const neverWatched = radarrMovies.filter(m => unwatchedMovies.find(({ title, added_at }) => m.title === title && getMonthsBetween(new Date(added_at * 1000), new Date()) >= monthsSinceAdded));

    _movies = neverDownloaded.concat(neverWatched);
    ids = _movies.map(x => x.id);
    console.log('Sure you want to delete these movies?:');
    _movies.map(x => console.log(x.title, 'added', getMonthsBetween(new Date(x.added), new Date()), 'months ago', `(id: ${x.id})`))
    const confirm = window.confirm('Sure you want to delete these movies? (Check console)');


    if(confirm) {
    console.log('OK deleting..');
    if(blacklistedRadarrIds.includes(ids[index])){
    console.log(`${_movies.find(m => m.id === ids[index]).title} is blacklisted. Skipping`);
    deleteMovie(ids[index + 1]);
    } else {
    if (ids.length) {
    console.log(`${percentage()} Deleting ${_movies.find(m => m.id === ids[index]).title}`);
    deleteMovie(ids[index]);
    } else {
    console.log('There doesn`t seem to be any movies to delete');
    }
    }
    } else {
    console.log('Aborted')
    }
    });
    }
    }