Advertisement
Peaser

bandcamp album ripper (python3)

Dec 29th, 2015
407
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.78 KB | None | 0 0
  1. import os, sys, re, json, urllib.request, urllib.parse, urllib.error, threading
  2. from functools import partial
  3. from PyQt4 import QtCore, QtGui
  4. from win32api import GetSystemMetrics
  5.  
  6. Dimensions = [512, 512]
  7. XY = [GetSystemMetrics (i)/2-(Dimensions[i]/2) for i in range(2)] #create window in center of screen
  8. XY += Dimensions
  9.  
  10. class Window(QtGui.QWidget):
  11.  
  12.     def __init__(self):
  13.         super(Window, self).__init__()
  14.         self.initUI()
  15.  
  16.     def initUI(self):
  17.         self.setGeometry(*XY)
  18.         self.setFixedSize(*Dimensions)
  19.         self.setWindowTitle("Bandcamp Ripper")
  20.         self.show()
  21.  
  22.         urlInput = QtGui.QLineEdit(self)
  23.         urlInput.show()
  24.  
  25.         scanInitialize = QtGui.QPushButton(self)
  26.         scanInitialize.setText("Fetch")
  27.  
  28.         scanInitialize.show()
  29.  
  30.         songListDisplay = QtGui.QTreeWidget(self)
  31.         songListDisplay.setHeaderLabels(["Name", "Url", "Download status"])
  32.         songListDisplay.show()
  33.  
  34.         urlInput.setPlaceholderText("Enter bandcamp album URL")
  35.  
  36.         toplayout = QtGui.QGridLayout(self)
  37.         toplayout.addWidget(scanInitialize, 0, 0)
  38.         toplayout.addWidget(urlInput,       0, 1)
  39.  
  40.         mainGroup = QtGui.QGroupBox(self)
  41.         mainGroup.setTitle("URL")
  42.         #mainGroup.setMinimumWidth(512)
  43.         mainGroup.setMinimumHeight(30)
  44.         mainGroup.setLayout(toplayout)
  45.         mainGroup.show()
  46.  
  47.         ArtistLabel = QtGui.QLabel(self)
  48.         ArtistLabel.setText("Artist")
  49.         FoundArtistLabel = QtGui.QLabel(self)
  50.         FoundArtistLabel.setText("...")
  51.  
  52.         AlbumLabel = QtGui.QLabel(self)
  53.         AlbumLabel.setText("Album Art")
  54.         FoundAlbumLabel = QtGui.QLabel(self)
  55.         FoundAlbumLabel.setText("...")
  56.  
  57.         NameLabel = QtGui.QLabel(self)
  58.         NameLabel.setText("Album Name")
  59.         FoundNameLabel = QtGui.QLabel(self)
  60.         FoundNameLabel.setText("...")
  61.  
  62.         SongLabel = QtGui.QLabel(self)
  63.         SongLabel.setText("Songs")
  64.         FoundSongLabel = QtGui.QLabel(self)
  65.         FoundSongLabel.setText("...")
  66.  
  67.         objectsFound = QtGui.QGridLayout(self)
  68.         objectsFound.addWidget(ArtistLabel,      0, 0)
  69.         objectsFound.addWidget(FoundArtistLabel, 0, 1)
  70.         objectsFound.addWidget(AlbumLabel,       1, 0)
  71.         objectsFound.addWidget(FoundAlbumLabel,  1, 1)
  72.         objectsFound.addWidget(NameLabel,        2, 0)
  73.         objectsFound.addWidget(FoundNameLabel,   2, 1)
  74.         objectsFound.addWidget(SongLabel,        3, 0)
  75.         objectsFound.addWidget(FoundSongLabel,   3, 1)
  76.  
  77.         statusBox = QtGui.QGroupBox(self)
  78.         statusBox.setTitle("Album scan status")
  79.         #statusBox.setMinimumWidth(512)
  80.         statusBox.setMinimumHeight(30)
  81.         statusBox.setLayout(objectsFound)
  82.         statusBox.show()
  83.  
  84.         downloadInitialize = QtGui.QPushButton(self)
  85.         downloadInitialize.setText("Begin Download")
  86.         downloadInitialize.setDisabled(True)
  87.  
  88.         MAINlayout = QtGui.QGridLayout(self)
  89.         MAINlayout.addWidget(mainGroup,          0, 0)
  90.         MAINlayout.addWidget(statusBox,          1, 0)
  91.         MAINlayout.addWidget(downloadInitialize, 2, 0)
  92.         MAINlayout.addWidget(songListDisplay,    3, 0)
  93.  
  94.         self.setLayout(MAINlayout)
  95.  
  96.         def confirm():
  97.             if not re.match("^https?:\/{2}.+\.?[bandcamp]?\.com\/album\/.+$", urlInput.text()): #Test if iput is valid URL
  98.                 QtGui.QMessageBox.warning(self, "Error", "Invalid Url\nValid example: http://artist.bandcamp.com/album/albumname")
  99.             else:
  100.                 url = str(urlInput.text())
  101.                 data = urllib.request.urlopen(url).read()
  102.                 toFind = {
  103.                     "Artist": {
  104.                         "Found": False,
  105.                         "Collected": None,
  106.                         "Pattern": 'BandData.+?{.+?name: "(.+?)".+?};',
  107.                         "Namespace": "artistName",
  108.                         "iPath": FoundArtistLabel
  109.                     },
  110.                     "Art": {
  111.                         "Found": False,
  112.                         "Collected": None,
  113.                         "Pattern": 'TralbumData.+?{.+?artFullsizeUrl: "(.+?)".+?};',
  114.                         "Namespace": "artData",
  115.                         "iPath": FoundAlbumLabel
  116.                     },
  117.                     "Album": {
  118.                         "Found": False,
  119.                         "Collected": None,
  120.                         "Pattern": 'EmbedData.+?{.+?album_title: "(.+?)".+?};',
  121.                         "Namespace": "albumName",
  122.                         "iPath": FoundNameLabel
  123.                     },
  124.                     "Songs": {
  125.                         "Found": False,
  126.                         "Collected": None,
  127.                         "Pattern": 'trackinfo.+?(\[.+?\])',
  128.                         "Namespace": "songsData",
  129.                         "iPath": FoundSongLabel
  130.                     }
  131.                 }
  132.  
  133.                 # I probably shouldn't put this here, but...
  134.                 def downloadInit():
  135.                     directory = toFind["Album"]["Collected"]+"/"
  136.                     if not os.path.exists(directory):
  137.                         os.mkdir(directory)
  138.                     urllib.request.urlretrieve(toFind["Art"]["Collected"], directory+"Album"+os.path.splitext(toFind["Art"]["Collected"])[1])
  139.                     # ^^ download cover art
  140.                     def threadedDL():
  141.                         root = songListDisplay.invisibleRootItem()
  142.                         def subThread(child_):
  143.                             rc = root.child(child_)
  144.                             rc.setText(2, "Downloading...")
  145.                             fileName = "{0} - {1}.mp3".format(toFind["Artist"]["Collected"], rc.text(0))
  146.                             urllib.request.urlretrieve("http:"+str(rc.text(1)), directory+fileName)
  147.                             rc.setText(2, "Done!")                            
  148.                         for i in range(root.childCount()):
  149.                             sub = threading.Thread(target=partial(subThread, i))
  150.                             #sub.daemon = True
  151.                             sub.start()
  152.                     t = threading.Thread(target=threadedDL)
  153.                     t.daemon = True
  154.                     t.start()
  155.  
  156.                 for subject in toFind:
  157.                     try:
  158.                         regex_data = re.findall(toFind[subject]["Pattern"], str(data), re.DOTALL)
  159.                         if len(regex_data) == 1:
  160.                             toFind[subject]["Collected"] = regex_data[0]
  161.                         else:
  162.                             toFind[subject]["Collected"] = list(reversed(sorted(regex_data,key=len)))[0]
  163.                         toFind[subject]["Found"] = True
  164.                         toFind[subject]["iPath"].setText("Found!")
  165.                     except Exception as e:
  166.                         QtGui.QMessageBox.warning(self, "Error", e)
  167.                 try:
  168.                     toFind["Songs"]["Collected"]=[(str(i["title"]), str(i["file"]['mp3-128'])) for i in json.loads(toFind["Songs"]["Collected"])]
  169.                 except Exception as e:
  170.                     QtGui.QMessageBox.warning(self, "Error", e)
  171.                 # ^^^^ Turn "songs" list into tuples formatted like (name, url)
  172.                 #scanInitializees into tree widget below...
  173.                 for i in toFind["Songs"]["Collected"]:
  174.                     sitem = QtGui.QTreeWidgetItem(list(i) + ["Pending"])
  175.                     songListDisplay.addTopLevelItem(sitem)
  176.                 downloadInitialize.setDisabled(False)
  177.                 downloadInitialize.clicked.connect(downloadInit)
  178.         scanInitialize.clicked.connect(confirm)
  179.  
  180.  
  181. def main():
  182.     ab = QtGui.QApplication(sys.argv)
  183.     ex = Window()
  184.     sys.exit(ab.exec_())
  185.  
  186. if __name__ == '__main__':
  187.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement